[09] 数组
1、基本概述
数组属于对象,它是相同数据类型元素的集合,这里的数据类型,既可以存储基本数据类型,也可以存储引用数据类型。
对于数组的声明,有两种方式:
- 数据类型 [ ] 数组变量名 (如 int [ ] arr)
- 数组类型 数组变量名 [ ] (如 int arr [ ])
虽然两者并没有本质上的区别,但从可读性上建议使用 int[ ] arr 的方式。
数组的创建方式有三种:
- 声明数组的同时,只指定其长度,数组中的值都为默认的初始化值(动态创建,可以结合for循环进行赋值)
- e.g. char[ ] arr = new char[10];
- 声明数组的同时,初始化其内部的值(静态创建)
- e.g. int[ ] arr = new int[ ]{1, 2, 3, 4, 5};
- 和第二种方式相同,但语法更简单(同上)
- e.g. int[ ] arr = {1, 2, 3, 4, 5};
注意:
- 数组初始化时必须直接或间接定义长度,且其长度一经定义不允改变
- 未定义元素值得数组,其元素初始化值跟数据类型有关,如int为0,char为'',String则为null
- 数组的长度是属性length,而String的长度是方法length()
- 数组是对象,所以直接赋值给另一个数组,实际上只是改变了引用,而不是复制
2、数组的访问和迭代
2.1 数组的访问
数组中单个元素的访问,使用 数组名 [索引] 的方式,比如 arr[2]; 将访问数组中第三个元素。
注意:
- 数组的索引从0开始
- 索引的数据类型是整型
- 索引最大值和数组长度始终差1
2.2 数组的迭代
2.2.1 for循环
int[] arr = new int[]{1, 2, 3, 4, 5, 6};
System.out.println(arr[0]);
System.out.println(arr[2]);
//数组的迭代
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
7
1
int[] arr = new int[]{1, 2, 3, 4, 5, 6};
2
System.out.println(arr[0]);
3
System.out.println(arr[2]);
4
//数组的迭代
5
for (int i = 0; i < arr.length; i++) {
6
System.out.println(arr[i]);
7
}
2.2.2 for each 增强for循环
int[] arr = new int[]{1, 2, 3, 4, 5, 6};
System.out.println(arr[0]);
System.out.println(arr[2]);
//数组的迭代
for (int ele : arr) {
System.out.println(ele);
}
7
1
int[] arr = new int[]{1, 2, 3, 4, 5, 6};
2
System.out.println(arr[0]);
3
System.out.println(arr[2]);
4
//数组的迭代
5
for (int ele : arr) {
6
System.out.println(ele);
7
}
for (数组元素的类型 临时变量名 : 数组的名字){ ... }
3、二维数组
二维数组,即数组中存储的元素也为数组,形如:int[][] arr = {{1}, {1, 2}, {1, 2, 3}};
二维数组的声明方式示例如下,仍然建议使用第一种:
- int [ ] [ ] arr
- int [ ] arr [ ]
- int arr [ ] [ ]
二维数组的创建方式示例如下:
- int [ ] [ ] arr = new int [ n ] [ m ];(n不可省略,即最外层数组长度必须定义,m表子数组长度,可以省略不定义)
- int [ ] [ ] arr = {{1,2,3,4}, {1,2,3,4}, {1,2,3,4}};
4、数组的拷贝
我们说过,想要拷贝数组,是不能直接通过赋值的,因为对象的缘故,只是改变了其引用,本质上并不是复制。
你可以使用循环赋值的方式来获得一个新的数组,但是这种方式未免太笨拙了一些。在JDK API的System类中,已经为我们提供了一个数组拷贝的静态方法:arraycopy
//从指定源数组,复制从指定位置开始,到指定数组的指定位置结束,复制指定长度个元素
arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
2
1
//从指定源数组,复制从指定位置开始,到指定数组的指定位置结束,复制指定长度个元素
2
arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
拷贝示例:
int[] arr1 = {10, 100, 1000};
int[] arr2 = {20, 200, 2000, 20000};
//从arr1[1]开始,赋值到arr2,从arr[2]开始,共复制2个元素
System.arraycopy(arr1, 1, arr2, 2, 2);
for (int bean : arr1) {
System.out.print(bean + ", ");
}
System.out.println();
for (int bean : arr2) {
System.out.print(bean + ", ");
}
//结果:
//10, 100, 1000,
//20, 200, 100, 1000,
17
1
int[] arr1 = {10, 100, 1000};
2
int[] arr2 = {20, 200, 2000, 20000};
3
4
//从arr1[1]开始,赋值到arr2,从arr[2]开始,共复制2个元素
5
System.arraycopy(arr1, 1, arr2, 2, 2);
6
7
for (int bean : arr1) {
8
System.out.print(bean + ", ");
9
}
10
System.out.println();
11
for (int bean : arr2) {
12
System.out.print(bean + ", ");
13
}
14
15
//结果:
16
//10, 100, 1000,
17
//20, 200, 100, 1000,
实际上,你还可以使用从Object上继承下来的clone方法,不过该方法是浅克隆:
- 浅克隆:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象
- 深克隆:被复制对象的所有变量都含有与原来的对象相同的值,而那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些
所以,为了避免出错,在某个数组的元素类型是基本数据类型时,完全可以使用clone方法,如果元素类型为其他对象,则使用时要慎重。
5、数组的常用操作
数组虽然属于对象,但是几乎没有自身的方法,基本上都是从Object类上继承下来的。需要数组的操作,要通过一个工具类中大量的静态方法来实现,Arrays类(注意有s)
5.1 数组转换为集合
Arrays有asList方法可以直接将数组转换为List:
String[] arr = {"zhangsan", "lisi", "wangwu"};
List<String> temp = Arrays.asList(arr);
for (String bean : temp) {
System.out.println(bean);
}
//输出
//zhangsan
//lisi
//wangwu
11
1
String[] arr = {"zhangsan", "lisi", "wangwu"};
2
List<String> temp = Arrays.asList(arr);
3
4
for (String bean : temp) {
5
System.out.println(bean);
6
}
7
8
//输出
9
//zhangsan
10
//lisi
11
//wangwu
如果要转换为Set,要利用其构造函数允许传入参数为Collection的子类,但注意乱序的同时会覆盖重复的元素:
String[] arr = {"zhangsan", "lisi", "wangwu", "wangwu"};
Set<String> temp = new HashSet<String>(Arrays.asList(arr));
for (String bean : temp) {
System.out.println(bean);
}
//输出
//wangwu
//lisi
//zhangsan
11
1
String[] arr = {"zhangsan", "lisi", "wangwu", "wangwu"};
2
Set<String> temp = new HashSet<String>(Arrays.asList(arr));
3
4
for (String bean : temp) {
5
System.out.println(bean);
6
}
7
8
//输出
9
//wangwu
10
//lisi
11
//zhangsan
如果数组的元素类型为基本数据类型,因为不是对象,而集合的对象必须为对象(这里方法中没有使用自动装箱),所以只能用笨办法:
int[] arr = {1, 3, 5, 2, 4, 6};
List<Integer> list = new ArrayList<Integer>();
for (int ele : arr) {
list.add(ele);
}
for (Integer bean : list) {
System.out.println(bean);
}
9
1
int[] arr = {1, 3, 5, 2, 4, 6};
2
List<Integer> list = new ArrayList<Integer>();
3
for (int ele : arr) {
4
list.add(ele);
5
}
6
7
for (Integer bean : list) {
8
System.out.println(bean);
9
}
5.2 判断数组是否包含某个元素
曲线救国的方式,先将数组转为List,通过List的contains来判断:
String[] arr = {"zhangsan", "lisi", "wangwu"};
boolean result = Arrays.asList(arr).contains("lisi");
System.out.println(result);
//结果
//true
x
1
String[] arr = {"zhangsan", "lisi", "wangwu"};
2
boolean result = Arrays.asList(arr).contains("lisi");
3
System.out.println(result);
4
5
//结果
6
//true
当然,也可以先转换为字符串,使用字符串的contains方法;亦或者自循环进行判断。