我们为什么需要数组?
我学的第一门编程语言时C语言,在C语言中是没有集合类型的,比较复杂的数据会用数组来保存,以至于我觉得数组是一种理所当然的必然存在。现在想一想,为什么需要用数组呢?我想答案是,当我们对有着同一数据类型的多个数据需要进行同一管理时,就可以靠数组来快捷实现。
数组简介
数组是相同类型数据的有序集合。数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。其中,每一个数据称作一个元素,每个元素可以通过一个索引(下标)来访问它们。数组的三个基本特点:
-
1.长度是确定的。数组一旦被创建,它的大小就是不可以改变的。
-
2.其元素必须是相同类型,不允许出现混合类型。
-
3.数组类型可以是任何数据类型,包括基本类型和引用类型。
数组声明与初始化
数组的声明实例:
double[] myList; // 首选的方法
或
double myList[]; // 效果相同,但不是首选方法,该风格是来自 C/C++ 语言
静态初始化
可以直接在定义数组的同时就为数组元素分配空间并赋值:
int[] myList = new int[] { 1,2,3,4,5 }; // 数组大小在初始化时固定,比如该数组只能存3个数
Man[] mans = { new Man(1, 1), new Man(2, 2) };// 静态初始化引用类型数组
动态初始化
数组定义与为数组元素分配空间并赋值的操作分开进行:
int[] myList = new int[5]; //预先定义指定的空间大小,此时数组中的每个值为null
myList[0] = 1;
myList[1] = 2;
myList[2] = 3;
myList[3] = 4;
myList[4] = 5;
默认初始化
数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化:
int a2[] = new int[2]; // 默认值:0,0
boolean[] b = new boolean[2]; // 默认值:false,false
String[] s = new String[2]; // 默认值:null, null
数组的遍历
数组元素下标的合法区间:[0, length-1],如果超出区间,则会在程序运行时出现越界异常。我们可以通过下标来遍历数组中的元素,遍历时可以读取元素的值或者修改元素的值。
当我们使用数组时,可以使用for循环来读取元素的值或者修改元素的,使用foreach循环只能进行读取(关于foreach循环可以阅读:《Java基础语法-foreach》),如下:
public class Test {
public static void main(String[] args){
int[] myList = new int[4];
// for循环,为数组元素赋值
for (int i = 0; i < myList.length; i++) {
myList[i] = i;
}
// for循环,打印所有数组元素
for (int i = 0; i < myList.length; i++) {
System.out.print(myList[i]);
}
System.out.println();
// foreach循环,打印所有数组元素
for (int i : myList) {
System.out.print(i);
}
}
}
---------------------------------------------------------------
输出结果为:
0123
0123
数组的拷贝
System类里也包含了一个static void arraycopy(object src,int srcpos,object dest, int destpos,int length)方法,该方法可以实现数组的拷贝,具体参数含义简单来说就是:System.arraycopy(源数组,源数组的起始位置,目标数组,目标数组的起始位置,要复制的元素数量)。
来个实例感受一下:
public class Test {
public static void main(String[] args) {
String[] myList1 = { "a", "b", "c", "d" };
String[] myList2 = new String[10];
System.arraycopy(myList1, // 源数组
1, // 源数组的起始位置,注意数组的下标从0开始哦
myList2, // 目标数组
5, // 目标数组的起始位置,注意数组的下标从0开始哦
2); // 要复制的元素数量
for (String string : myList2) {
System.out.print(string+"\t");
}
}
}
-----------------------------------------------------
输出结果为:
null null null null null b c null null null
Arrays类
JDK提供的java.util.Arrays类,包含了常用的数组操作,是我们日常开发中的一个常用类。Arrays类包含了:排序、查找、填充、打印内容等常见的操作。常用方法:
方法 | 说明 |
---|---|
String toString(int[] a) | 打印数组元素的值 ,传入参数为待打印数组 |
void sort(int[] a) | 数组元素的排序 ,引用类型需实现Comparable |
int binarySearch(long[] a, long key) | 二分法查找指定元素,返回查找元素的下标 |
void fill(long[] a, long val) | 对数组进行填充 |
当然,这些方法里的变量类型可以是所有数据类型,Arrays中有很多重载。
注意这里的toString方法,与Object的toString是不同的,并不是重写了Object的toString,而是带有参数的重载。
来个Arrays类的实例:
public class Test {
public static void main(String[] args) {
String[] myList = { "b", "c", "d", "a" };
System.out.println(myList); //直接打印数组
System.out.println(Arrays.toString(myList)); // 打印数组元素的值
Arrays.sort(myList);//使用sort方法进行排序
System.out.println(Arrays.toString(myList)); // 打印数组元素的值;
System.out.println("该元素的索引:"+Arrays.binarySearch(myList, "c"));//二分法查找指定元素
Arrays.fill(myList, 1, 3, "e"); //将[1,3)索引的元素替换为"e";
System.out.println(Arrays.toString(myList));
}
}
--------------------------------------------------------------------
输出结果为:
[Ljava.lang.String;@7852e922
[b, c, d, a]
[a, b, c, d]
该元素的索引:2
[a, e, e, d]
多维数组
二维及多维数组,就是数组当中的每一个元素,又是一个数组。(俄罗斯套娃…)但是实际开发中用的非常少。最多到二维数组(一般使用容器,二维数组用的都很少)。
声明与一维数组类似;初始化时,先初始化第一层,再第二层,以此类推;遍历时就使用嵌套循环,一层一层取出来。这里可能会觉得有点绕,那就多敲代码玩一玩,试一试,实践出真知,来个实例:
String[][] s = null; // 声明
s = new String[2][]; //初始化该数组,预先定义指定的空间大小:数组中存了2个数组元素。
//new String[2][],中的第二个[]中并不不能约束第二维的元素个数
s[0] = new String[2]; //初始化数组中的第0号元素,该元素也为数组
s[1] = new String[3]; //初始化数组中的第1号元素,该元素也为数组
s[0][0] = new String("Good"); //为二维数组的第0号元素的0号元素赋值
s[0][1] = new String("Luck"); //...一个个来
s[1][0] = new String("to");
s[1][1] = new String("you");
s[1][2] = new String("!");
for (String[] strings : s) {
for (String strings2 : strings) { //嵌套foreach来遍历
System.out.println(strings2);
}
}
-------------------------------------------
输出结果为:
Good
Luck
to
you
!
关于嵌套循环遍历可能还好理解一些,关于声明,我这里用个人理解再阐述一下:
如果我们想声明一个一维数组,那么:
- 1.首先,它是一个数组,所以我们写: [ ] 来表示是数组。
- 2.然后数组中装的是int类型,所以我们再写:[ ] int 来表示是装int类型的数组。
- 3.再给这个声明数组取个名字,所以我们写:[ ] int myList,来表示是一个叫myList的,装int类型的数组。但是这样写不好看,所以Java规定了,我们得变形成:int[ ] myList 来声明。
- 4.以上声明已经完成,然后我们进行初始化:int[ ] myList = new int[2];注意,这里使用了new关键字,能被new的都是对象,而int时基本数据类型,不能被new。我们可以理解为:new [ ],是new的一个数组,然后数组中为 int 类型,元素个数为 2 ,即 new [ ] int 2,变形:new int[2],即int[ ] myList = new int[2];自此分配空间完成,可以进行赋值。
那当我们想声明一个二维数组,参照上面的步骤:
- 1.首先,它是一个数组,所以我们写: [ ] 来表示是数组。
- 2.然后数组中装的是数组类型,所以我们再写:[ ] [ ] 来表示是装int类型的数组。
- 3.此时第二个数组还没声明完,此数组中装的是int类型,所以我们再写:[ ] [ ] int 来表示是装int类型的数组。(若想声明更高维数组,则把int改为 [ ] 重复此步骤,直到最后一维数组内装元素的类型不再是数组)
- 4.再给这个声明数组取个名字,所以我们写:[ ] [ ] int myList。根据Java的语法格式规定,所以变形为:int[ ] [ ] myList 来声明。
- 5.以上声明已经完成,然后我们进行初始化:先 new 第一维数组: new [ ] ,数组中为数组类型:[ ] ,元素个数为2,即 new [ ] [ ] 2 。但数组是不能单独存在的,必须是某一个数据类型的数组,所以加上最后一维的数据类型:int。即写为:new int[2][ ]。注意,此时第二维数组并没有被new出来,一个new关键字不能new出两个对象。所有我们还要继续new第二维。
- 6.初始化一个数组:new int[3];(三个元素)再将new出的数组赋值给这个二维数组,即:myList[0] = new int[3];
- 7.再初始化一个数组:new int[4];(四个元素)再将new出的数组赋值给这个二维数组,即:myList[1] = new int[4];至此,myList数组全部装满,这才分配空间完成,可以进行赋值。
以上,是我的个人理解,若理解存在错误欢迎指正。