数组是一组数据的容器。该组数据每个数据又称元素,元素有下标。数组的下标从0开始,最大是数组的元素个数减1。数组一旦初始化后,长度不可变
数组中,每个元素都会开辟空间,且元素的空间都是相邻的,这决定了在数组中查找数据时的高效率。
(二)数组的声明
数据类型[] 数组名;
String[] names;//推荐 String names[];
(三)数组初始化
1.静态初始化
静态初始化指在初始化时元素由程序员指定,系统根据元素自行确定数组的长度。
//静态初始化一 String[] names = new String[]{"王一","王二","王三"}; //静态初始化二(先声明,后初始化) String[] names; names = new String[]{"王一","王二","王三"}; //静态初始化三(对一的简化) String[] names = {"王一","王二","王三"};
图解:该图为一维数组静态初始化在内存中运行的图解。
①执行main方法首先在方法区中加载该方法的.class文件,②随之,JVM会扫描该类里所有的常量,并将其存放到常量池里。③JVM调用main方法,并在栈中开辟空间存储main方法的局部变量。④初始化中new String[](new int[] / new boolean[]...)新建数组对象存放在堆里,对象内部存放元素的地址。⑤将对象的地址赋值给一维数组names,,names作为main方法中的局部变量存放在栈内。
⑥names[1] = "李四" --> 将0x44赋值给对象中0x22所在的位置,再将其赋值给str,实现数组元素的设置。
2.动态初始化
动态初始化指在初始化时数组长度由程序员指定,系统根据长度分配元素。
//动态初始化一 String[] names = new String[5]; //动态初始化二(先声明后初始化) String[] names; names = new String[5];
不同数据类型系统分配的元素
数据类型 | 默认值 |
---|---|
整型 | 0 |
浮点型 | 0.0 |
字符型 | ‘ ’ |
布尔类型 | false |
引用类型(除基本数据类型以外的其他数据) | null(空) |
2.静态初始化 vs 动态初始化
知道什么用什么
数组元素 --- 静态初始化
数组长度 --- 动态初始化
注意:
一维数组是引用数据类型
int[]是引用数据类型,但是其中的元素是基本数据类型的
(四)数组的使用
1.下标设置元素
//通过下标设置元素 names[1] = "李四";
2.下标获取元素
//通过下标获取元素 String str = names[1];
3.获取元素个数
//获取元素个数 int len = names.length;
4.遍历元素
(1)for循环
for(int i = 0;i<names.length;i++){ System.out.println(names[i]); }
(2)增强for循环/foreach
for(String element:names){ System.out.println(element); }
(3)for vs foreach
for | foreach |
---|---|
遍历时使用到下标 | 遍历时不使用下标 |
(五)数组的复制
1.浅表复制
将源数组直接赋值给新数组。也就是将源数组的地址复制给新数组。
//源数组 String[] arr = {"王一","王二","王三","王四"}; //新数组 String[] newArr = arr;
但是浅表复制存在缺点:修改了源数组之后,新数组也会随之改变
2.深表复制
将源数组的元素遍历赋值给新数组。
//源数组 String[] arr = {"王一","王二","王三","王四"}; //新数组:定义一个与源数组相同长度的新数组 String[] newArr = new String[arr.length]; //将源数组中的元素遍历赋值给新数组 for(int i = 0;i<arr.length;i++){ newArr[i] = arr[i]; }
深表复制,改变源数组的元素,新数组元素不会发生改变。
(六)数组的扩容
Java中对数组的操作只有改查,没有增删。因为数组作为容器一旦确定元素,其长度也就固定了。
此处扩容是通过定义一个新的数组(长度比源数组长),然后将新数组的地址复制给源数组,实现源数组的扩容。
例如:实现扩容为原来数组长度的1.5倍
public class test06{ public static void main(String[] args){ //源数组 String[] arr = {"王一","王二","王三","王四"}; //计算源数组长度 int oldCapacity = arr.length; int newCapacity = oldCapacity+(oldCapacity>>1); //创建新数组 String[] newArr = new String[newCapacity]; //将源数组所有元素赋值给新数组 for(int i=0;i<arr.length;i++){ newArr[i] = arr[i]; } //将新数组的地址赋值给源数组 arr = newArr; //遍历源数组 for(String element:arr){ System.out.println(element); } } }
(七)数组的删除
数组的删除是通过定义一个比源数组短的新数组,将源数组中除了某元素的其他元素赋值给新数组,把新数组的地址赋值给源数组来实现
public class test07{ public static void main(String[] args){ //源数组 String[] arr = {"王一","王二","王三","王四"}; //创建新数组:新数组长度比源数组少1(对比删除一个元素) String[] newArr = new String[arr.length-1]; //将源数组除了“王二”的元素赋值给新数组 int index = 0; for(int i=0;i<arr.length;i++){ if(!arr[i].equals("王二")){ newArr[index] = arr[i]; index++; } } //将新数组的地址赋值给源数组 arr = newArr; //遍历源数组 for(String element:arr){ System.out.println(element); } }
缺点:这种删除会让数组的空间越来越小,没有考虑到增加元素
基于此种状况,我们采用数组元素移动的方式,将被删除元素后边的元素往前移动。
public class test08{ public static void main(String[] args){ //源数组 String[] arr = {"王一","王二","王三","王四"}; //把要删除的元素后面的元素往前移 for(int i = 0;i<arr.length-1;i++){ arr[i] = arr[i+1]; } //把最后一个元素赋值为null arr[arr.length-1] = null; //遍历源数组 for(String element:arr){ System.out.println(element); } } }