一、数组简介
概念:是一种容器,可以同时存放多个数据值。
数组的特点:
- 数组是一种引用数据类型
- 数组当中的多个数据,类型必须统一(或者是当前类型的子类,例如:Object[]可以存放任意的数组类型,因为java中所有的类都是Object的子类)
- 数组的长度在程序运行期间不可改变。
- 数组的索引是从0开始的,一直到n-1(这个数组的长度为n);
- 数组一旦在内存中创建(不仅创建了储存数组地址的变量,而且还要向系统要到固定长度的空间地址)了,长度就无法改变了!
数组的初始化
- 一、动态初始化(指定长度):
基本格式:数据类型[] 数组名称 = new 数据类型[数组长度];
class Test {
public static void main(String[] args){
/**一步到位@*@*@*@ 推荐写法 @*@*@*@*/
int[] array1 = new int[10];
/**分开写*/
int[] array2;
array2 = new int[10];
/**错误的写法
int[] array3;
array3 = {1, 2, 3, 4};
*/
}
}
注意:使用动态数组初始化数组的时候,其中的元素会有一个默认值,
初始化数据类型 | 整型:byte、short、int、long | 浮点数:double、float | 字符:char | boolean:true、false | 引用类型(对象) |
---|---|---|---|---|---|
默认值 | 0 | 0.0 | '\u0000' | false | null |
- 二、静态初始化(指定内容):
基本格式:数据类型[] 数组名称 = new 数据类型[] {item1, item2, ...};
提示:虽然静态初始化没有直接告诉长度,但是根据大括号里面的元素具体内容推算出数组的长度,这个是JVM底层的优化。
class Test {
public static void main(String[] args){
/**一步到位*/
int[] array1 = new int[]{1, 2, 3, 4, 5};
/**一步到位的简写形式@*@*@*@ 推荐写法 @*@*@*@**/
int[] array2 = {1, 2, 4, 5, 6};
/**分开写*/
int[] array3;
array3 = new int[]{1, 2, 3, 4, 5};
/**错误的写法如下:
int[] array4;
array4 = {1, 2, 4, 5, 6};
*/
}
}
注意:直接打印数组的名称,得到的结果是数组类型与内存地址哈希值的拼接(其实在源码中,这个功能是在toString()这个方法中定义的,打印一个对象名,实际就是调用的这个方法,可以对这个方法进行多态操作,实现自己想要的效果)
二、以一维数组为例深入理解数组的引用(地址)
Java的内存划分
Java的内存划分主要分为5,个部分--> 栈(Stack)、堆(Heap)、方法区(Method Area)、本地方法查找栈(Native Method Stack)、寄存器(pc Register);一个class文件执行的大致过程是 (提醒:这只是逻辑上的执行,这层逻辑封装了底层操作系统的具体调用以及具体的物理电路逻辑):JVM将.class字节码文件加载方法区(就是一堆字符串),然后解析,将方法压入栈中 (这个方法区有其他的数据结构保存当前变量以及变量值,我猜是HashMap这种数据结构,如果错误请指出)在执行中如果由遇到方法2,则将方法2压入的栈中,直到这个方法执行完了,然后又把之前的方法出栈继续执行。如果遇到new操作,则在另一个叫做内存区(堆这种数据结构)中创建并入堆一个对象,并将地址赋值给相关的变量。
1. 一个数组从创建到操作经历了哪些事?
2. 两个同的数组
3. 两个变量指向同一个数组
必须深入理解数组的引用,变量中储存的是数组对应的内存地址,如果对数组变量进行赋值操作,比如有个数组
int[] a = new int[3]; a = new int[]{1,2,3,4}
,对于这种情况,变量a指向一个新的长度为4的数组!
操作数组的一些注意事项:
数组的索引编号从0开始,一直到“数组的长度-1”为止。如果访问索引编号并不存在,抛出越界异常ArrayIndexOutOfBoundsException
所有的引用类型变量,都可以赋值为一个null值。但是代表其中什么都没有。数组必须进行new初始化才能使用其中的元素。如果只是赋值了一个null,没有进行new创建,那么将会发生:空指针异常 NullPointerException
如何获取数组的长度,格式:数组名称.length
数组可以作为方法的参数。当调用方法的时候,向方法的小括号进行传参,传递进去的其实是数组的地址值。
一个方法可以有0、1、多个参数;但是只能有0或者1个返回值,不能有多个返回值。如果希望一个方法当中产生了多个结果数据进行返回,怎么办?解决方案:使用一个数组作为返回值类型即可。任何数据类型都能作为方法的参数类型,或者返回值类型。数组作为方法的参数,传递进去的其实是数组的地址值。数组作为方法的返回值,返回的其实也是数组的地址值。
三、二维数组
二维数组,顾名思义,就是一个数组中的元素也是一个数组,二维数组的第一层索引一定是一个对应数据类型的引用(一维的数组的引用),第二个索引可能是个引用也可能是个基本数据类型
二维数组的定义方式与使用方法
public class Test {
public static void main(String[] args) {
/**一、动态初始化(指定长度)*/
int[][] array1 = new int[2][2];// @*@*@*@*@ 推荐方式1 @*@*@*@*@
int[][] array2 = new int[][]{{1,2,3}, {2,3,4}};
int[][] array3 = {{1,2,3},{5,6,7}};// @*@*@*@*@ 推荐方式2 @*@*@*@*@
int[][] array4;
array4= new int[][]{{1,4,5},{4,5,6}};
/**二、静态初始化(不指定长度),第一层索引必须制定*/
int[][] array5 = new int[5][];
int[][] array6;
array6 = new int[5][];
}
}
我利用二维数组举了一个实际问题的栗子,有点难度哦!
黑马中学高三二班进行了一个期中考试,有一个5人小分队,他们的成绩如下score,对应的课程为subjects;对应的名字为studentsName;请计算出并输出①这5个同学的各自的最高分?②每一位同学的平均成绩?③每一科的最高分?④每一科的平均分?
public class Test {
public static void main(String[] args) {
double[][] score = {
{110, 120, 110, 80, 69, 59},
{97, 130, 120, 80, 65, 60},
{107, 145, 119, 80, 64, 55},
{99, 150, 130, 80, 66, 52},
{112, 150, 99, 80, 68, 56}
};
String[] subjects = {"语文", "数学", "英语", "物理", "生物", "化学"};
String[] studentsName = {"李逍遥", "梅长苏", "景天", "蒙毅", "宁采臣"};
statisticsScore(score, subjects, studentsName);
}
public static void statisticsScore(double[][] score, String[] subjects, String[] studentsName) {
// 记录每一位同学的最高分
double[] highScoreStudent = new double[score.length];
// 记录每一位同学的平均成绩
double[] averageScoreStudent = new double[score.length];
// 记录每一科的最高分
double[] hightScoreSubject = new double[score[0].length];
// 记录每一科的平均分
double[] averageScoreSubject = new double[score[0].length];
// 计算每一位学生的信息----->横向遍历
for(int i = 0; i < score.length; i ++) {
double sumScoreStu = 0; // 累计当前同学的总分
for(int j = 0; j < score[i].length; j ++) {
// 记录当前同学的最高分
if(score[i][j] > highScoreStudent[i])
highScoreStudent[i] = score[i][j];
// 累计总分
sumScoreStu += score[i][j];
}
// 计算并记录当前同学的平均分
averageScoreStudent[i] = sumScoreStu / score[i].length;
}
// 计算每一门学科的信息----->纵向遍历
for(int i = 0; i < score[0].length; i ++) {
double sumScoreSub = 0; // 累计当前学科的总分
for(int j = 0; j < score.length; j ++) {
if(score[j][i] > hightScoreSubject[i])
hightScoreSubject[i] = score[j][i];
sumScoreSub += score[j][i];
}
averageScoreSubject[i] = sumScoreSub / score.length;
}
printMsg(subjects, studentsName, highScoreStudent, averageScoreStudent,
hightScoreSubject, averageScoreSubject);
}
public static void printMsg(String[] subjects, // 学科名称
String[] studentsName, // 同学姓名
double[] highScoreStudent, // 同学最高成绩
double[] averageScoreStudent, // 同学平均成绩
double[] hightScoreSubject, // 学科最高分
double[] averageScoreSubject) { // 学科平均分
System.out.println("*************************** 每一位同学的信息 ***************************");
System.out.println("---------------------------------------------------------------------");
System.out.print("| 学生姓名 | ");
for(int i = 0; i < studentsName.length; i ++) {
System.out.printf("%5s\t | ", studentsName[i]);
}
System.out.println();
System.out.println("---------------------------------------------------------------------");
System.out.print("| 最高成绩 | ");
for(int i = 0; i < highScoreStudent.length; i ++) {
System.out.printf("%5.2f\t | ", highScoreStudent[i]);
}
System.out.println();
System.out.println("---------------------------------------------------------------------");
System.out.print("| 平均成绩 | ");
for(int i = 0; i < averageScoreStudent.length; i ++) {
System.out.printf("%5.2f\t | ", averageScoreStudent[i]);
}
System.out.println();
System.out.println("---------------------------------------------------------------------");
System.out.println();
System.out.println("*************************** 每一个学科的信息 ***************************");
System.out.println("--------------------------------------------------------------------------------");
System.out.print("| 学科名称 | ");
for(int i = 0; i < subjects.length; i ++) {
System.out.printf("%5s\t | ", subjects[i]);
}
System.out.println();
System.out.println("--------------------------------------------------------------------------------");
System.out.print("| 最高成绩 | ");
for(int i = 0; i < hightScoreSubject.length; i ++) {
System.out.printf("%5.2f\t | ", hightScoreSubject[i]);
}
System.out.println();
System.out.println("--------------------------------------------------------------------------------");
System.out.print("| 平均成绩 | ");
for(int i = 0; i < averageScoreSubject.length; i ++) {
System.out.printf("%5.2f\t | ", averageScoreSubject[i]);
}
System.out.println();
System.out.println("--------------------------------------------------------------------------------");
}
}
输出结果(非常像一个数据库查询的结果)
四、多维数组
多维数组就是指数组的元素层层嵌套数组。在定义的时候,第一索引必须指定。执行索引之间不能不能指定索引;多维数组除了最后一层可以储存对象和基本数据类型,其他层次的必须储存对应类型的引用(对应维度的数组引用)
举一个栗子
public class Test {
public static void main(String[] args) {
/**多维数组,以一个四维数组为栗子*/
/**正确的写法*/
int[][][][] arrays1 = new int[4][][][];
int[][][][] arrays2 = new int[4][3][][];
int[][][][] arrays3 = new int[4][3][2][];
int[][][][] arrays4 = new int[4][3][2][1];
arrays4[4][3] = new int[7][3]; // 储存对应类型的引用
/**错误的写法
int[][][][] arrays5 = new int[][][][];
int[][][][] arrays6 = new int[][3][][];
int[][][][] arrays7 = new int[4][][2][];
*/
}
}