1、数组概述
数组,是多个相同类型数据按一定顺序排列的集合,并使用一个名字命名,并通过编号的方式对这些数据进行统一管理。
1.1、数组的相关概念
(1)数组名
(2)数组元素 //数组元素就是多个相同类型数据中的一个
(3)索引(角标,下标)
(4)数组的长度 //数组元素的个数
1.2、数组特点
(1)数组本身是引用数据类型,但数组的元素可以是基本数据类型(也可以是引用数据类型)。
说明:如果元素是基本数据类型,数组可以直接在内存中分配好内存空间。如果元素是引用数据类型(常见的是字符串),数组则存放元素的指针。另外,既然数组是引用,本身可以看成一个对象,自然数组就会有自己的属性和方法
(2)数组的长度一旦确定,就不能修改。(想添加元素,只能造一个更长的新数组,然后将就数组元素复制过去)
(3)创建数组对象会在内存中开辟一整块连续的空间,数组名就是引用这块连续空间的首地址。(区别链表,链表就是在内存中不连续的,但是链表末尾有个指向下一个链表的指针)
1.3、数组分类
按照维度:一位数组、二维数组。。。
2、一维数组的使用
2.1 一维数组的声明和初始化
(1)创建数组
语法: 数据类型[ ] 数组名; //声明一个 数据类型为 数据类型 数组名为 数组名 的长度未定义的数组。
静态初始化数组 (数组的初始化和数组元素的赋值同时进行)语法:
数组名 = new 数据类型 [ ] {元素1,元素2,元素3}; //new是引用数据类型的标志,此时数组长度为3,数组元素也已确定
exp: int[ ] = ids; //声明一个数组为ids,数据类型为int 长度未定义的数组
ids = new int[ ] {1,2,3,4}; // 将int型数组ids 初始化为 1,2,3,4 此时数组长度为4
同样 声明和初始化 可连写成一句代码:
数据类型[ ] 数组名 = 【new 数据类型 [ ]】 {元素1,元素2,元素3};
说明:由于两边数据类型是一样的,因此如果将声明和初始化写在一起,可以省略【】中的语句(编译器可以推断)
动态初始化数组 (数组的初始化和数组元素的赋值分开进行,即先声明数组,后面视情添加数组元素)语法: 数组名 = new 数据类型[元素长度] ;
exp: String[ ] names = new String[5]; //初始化一个长度为5,名为names的数组。数组元素暂时未添加
注意:数组一旦初始化完成,其长度就确定了。(即内存分配完成)
同样 声明和初始化 可连写成一句代码:
数据类型[ ] 数组名 = new 数据类型 [元素长度 ];
扩展:数组的默认初始化值 动态初始化数组并没给数组元素赋值 此时系统分配默认初始化值,分配拟规则如下:
(1)数组元素为整型(byte short int long): 默认初始化为 0
(2)数组元素为浮点型(float double):默认初始化为0.0
(3)数组元素为字符型(char):默认初始化为0 (AscII 的0 对应的符号)
(4)数组元素为boolean型:默认初始化为false (boolean值false的底层是0)
(5)数组元素为引用数据类型(String,类):默认初始化为null
2.2 如何调用指定位置的元素
规则: 通过索引(角标)调用,数组的索引从0开始,到(数组长度-1)结束
语法: 数组名[索引] = 元素值 ; //给指定索引的数组元素赋值
exp:
String[] names = new String[5]; //动态初始化一个长度为5,名叫names的数组
names[0]="蒋总裁"; //给names数组第一个元素赋值 "蒋总裁"
2.3 如何获取数组长度 length属性
数组本身也是对象,就是[]对象。既然是对象就有属性和方法。数组长度属性length
语法: 数组名.length; //返回当前数组长度
exp: names.length;// 返回names数组的长度
2.4 数组的遍历 (for循环应用 非新知识点)
语法: for(int i=0; i<数组名.length; i++){} //遍历 数组名 的数组
2.5 数组的内存解析
(1)JVM常用内存模型
(2)数组内存解析 只用了栈和堆
JAVA的垃圾回收算法发现栈里面的指针和堆切断后,会自动回收堆中的垃圾。
注意:刘德华,张学友是String类,又是引用,非基本数据类型,会继续用指针指向常量池。这里只是为了看着更直观,因此写在数组里面。具体引用数据类型数组,看下面。
(3)对象数组类型解析 (元素是引用数据类型的数组)
3、二维数组的使用 (并非新知识点,数组的应用而已)
3.1 二维数组的理解:由于数组本身就是引用数据类型,数组的元素可以是基本数据类型,也可以是一个引用,类或数组。
如果一个一维数组array1,恰好作为另一个一维数组array2的元素存在。那么,array2这就是二维数组。
从数组底层的运行机制来看,并没有多维数组。所谓多维数组,就是一维数组多次嵌套。
3.2 二维数组的声明和初始化
(1)二维数组声明
语法: 数据类型[ ][ ] 数组名 ; //声明一个 数组名为 数组名 的二维数组
静态初始化:语法: 数组名 = new 数据类型[ ][ ]{{元素1,元素2,元素3},{元素4,元素5},{元素6}};
exp: int[ ][ ] = arr; //声明一个二维数组,名叫arr
arr = new int[ ][ ]{{1,2,3},{4,5},{6,7,8}}; //静态初始化数组
动态初始化:语法: 数组名 = new 数据类型[最外层元素个数][第二层元素个数];
说明:可以近似的看成 行*列 ,第二层(内层)元素个数(列数)可以暂时为空,由于内层为空,即没初始化,就没地址给外层数组元素,因此此时外层数组元素为null,这时如果要调用内层元素,就会触发空指针异常(外层元素为null,不是指向内层元素的指针)
扩展:二维数组的默认初始化值
(1)数组元素为整型
int[ ][ ] arr = new int[ ][ ]{{1,2,3},{4,5},{6,7,8}};
外层元素默认值:外层元素所在的内存地址值。即arr[0]: 为arr[0] 的 内存地址0XYYZZ
内层元素的默认值:int型嘛,自然默认值为0。
(2)数组元素为浮点型:同理,外层默认值为地址值。内层默认值为0.0
(3)数组元素为字符型:同理,外层默认值为地址值。内存默认值为0(ASCII的0)
(4)数组元素为布尔型:同理,外层默认值为地址值。内存默认值为false(false底层为0)
(5)数组元素为引用型(比如String):同理,外层默认值为地址值。内存默认值为null
特殊情况:数据类型 [ ][ ] 数组名 = new 数组名[元素长度][ 空 ];
exp: int[ ][ ] arr = new arr[5][ ];
由于没有初始化过内层数组,所以也不会分配地址给外层数组,此时外层元素默认值为null,一旦调用内层元素就会报错(空指针异常)。
3.3 如何调用二维数组指定位置的元素
规则: 通过索引(角标)调用,数组的索引从0开始,到(数组长度-1)结束。先调用最外层,依次向内调用。
语法: 数组名[外层索引][内层索引] = 元素值 ; //给指定索引的数组元素赋值
exp: int[ ][ ] arr = new int[ ][ ]{{1,2,3},{4,5},{6,7,8}}; //静态初始化数组
System.out.println(arr[0][1]); //0代表最外层的0,即第一个大括号,1代表第二层的第二个,即2
3.4 获取二维数组长度
同样适用数组的 length属性。前面讲过,JAVA底层并不存在多维数组(多维数组只是一维数组的嵌套而已)。所以length属性只针对数组的最外层有几个元素。至于每个元素又可以展开成多少孙元素,length属性就不管了。
语法: 数组名.length; //返回当前数组最外层的长度
exp: int[ ][ ] arr = new int[ ][ ]{{1,2,3},{4,5},{6,7,8}}; //静态初始化数组
System.out.println(arr.length); //输出3,最外层只有3个元素,所以长度为3
System.out.println(arr[1].length); //输出2,{4,5} 里面只有2个元素
3.5 二维数组的遍历 嵌套for循环
for(int i=0;i<arr.length;i++) {
for(int j=0; j<arr[i].length; j++){
System.out.print(arr[i][j]);
}
}
3.6 二维数组内存解析