目录
前言
什么是数组?
可能在不同的编程语言上已经用过很多次“数组”,但数组的定义是什么,这里截取了百度上的定义:数组(Array)是有序的元素序列。 若将有限个类型相同的变量的集合命名,那么这个名称为数组名。
在java中,虽然基本的数据类型不是对象,但由基本数据类型组成的数组却是对象。下面将具体介绍java中数组的创建及使用。
1. 数组的创建
1.1 一维数组的创建及使用
数组声明:给出数组名字和元素的数据类型,但这时候还不能对数组进行访问,因为还未给数组分配内存。
// 数组声明的语法
// 数组元素类型[] 数组名称;
int[] arr;
数组内存分配:作为java的对象之一,数组允许使用new关键字进行内存分配。
// 数组内存分配的语法
// 数组名称 = new 数组元素类型[数组元素个数];
arr = new int[5];
数组声明的同时进行内存分配
// 数组内存分配的语法
// 数组类型 数组名称 = new 数组元素类型[数组元素个数];
int[] arr = new int[5];
注意,使用new关键字为数组分配内存的时候,整型数组中各个元素的初始值都为0。
数组初始化:通常有两种形式,用逗号隔开元素后,系统会自动为其分配内存。
int[] arr1 = {1,2,3,4,5,6,7};
int[] arr2 = new int[]{1,2,3,4,5,6,7};
除了上述创建数组的方法外,还有一种常见的创建数组的语法:
// 数组内存分配的语法
// 数组类型 数组名称 = new 数组元素类型[数组元素个数];
int arr[] = new int[5];
虽然也能成功创建数组,但这类写法是顺应了C/C++的语法,通常更推荐使用 int[] arr
这种方式,因为它符合Java社区的普遍约定,代码的可读性和一致性更好。
1.2 二维数组的创建及使用
与一维数组的创建方式类似,二维数组即多一个维度:
// 声明语法
// type[][] arrayname = {value1, value2, value3};
int[][] arr = {{1,2,3},{4,5,6}};
或者也可以利用坐标,对数组每个位置上的值进行初始化:
int[][] arr = new int[2][3];
arr[0][0] = 1;
arr[0][1] = 2;
arr[0][2] = 3;
arr[1][0] = 4;
arr[1][1] = 5;
arr[1][2] = 6;
二维数组的使用则同样可以通过上述坐标进行选择,或者可以通过俩for循环进行遍历,在这里也展示一个能够运行的类,诸君可自取。
public class HelloWorld{
public static void main(String[] args) {
System.out.println("Hello World");
int[][] arr = {{1,2,3},{4,5,6}};
for (int i=0; i<arr.length; i++){
for (int j=0; j<arr[i].length; j++){
System.out.print(arr[i][j]);
}
System.out.println();
}
}
}
// 输出结果如下:
// Hello World
// 123
// 456
2. 数组的基本操作
这一部分常用方法都比较简单,直接上代码实例!
2.1 遍历
常用的遍历方法即for循环,这里就不赘述了。另一种较为简洁的写法foreach语句,因为平时用的稍少,在这里记录如下:
public class HelloWorld{
public static void main(String[] args) {
int[][] arr = {{1,2,3},{4,5,6}};
for (int[] x:arr) {
for (int e:x) {
System.out.print(e);
}
System.out.println();
}
}
}
// 输出结果如下:
// 123
// 456
在这里面,int[] x : arr 即依次取arr的每一行,而 int e : x 则依次取 x 中的每一列。
2.2 填充替换数组元素
数组填充可以有两种方式,一种是填充到所有位置,一种是填充到指定范围。
// 填充到所有位置
// Arrays.fill(Type[] array, Type value)
// Type[] array 表示原数组
// Type value 表示用于替换的值
// 示例
import java.util.Arrays;
public class Fillin{
public static void main(String[] args) {
int[] arr = {1,2,3,4,5};
Arrays.fill(arr, 3);
for (int e:arr) {
System.out.print(e);
}
}
}
// 输出为33333
// 填充到指定位置
// Arrays.fill(Type[] array, int startIndex, int endIndex, Type value)
// [startIndex, endIndex)分别表示起始位置和最终位置,左闭右开
// 示例
import java.util.Arrays;
public class Fillin2{
public static void main(String[] args) {
int[] arr = {1,2,3,4,5};
Arrays.fill(arr, 1, 3, 9);
for (int e:arr) {
System.out.print(e);
}
}
}
// 输出为19945
注意:在指定位置填充的方法中,[startIndex, endIndex) 是左闭右开,也就是左侧坐标包括在内,而右侧不包括在内。
2.3 数组排序
最基础的就是 sort 升序排序:
import java.util.Arrays;
public class SortArr{
public static void main(String[] args) {
int[] arr = {5,2,0,1,3,1,4}; // 这不是马上七夕了,祝大家有情人眷属终成,白头依老。
Arrays.sort(arr); // 自然升序排序
for (int e:arr) {
System.out.print(e);
}
}
}
// 输出值:0112345
停杯投箸,要怎么才能实现sort的降序排序呢?感谢http://t.csdnimg.cn/jgPq3,这位作者给出了详细的实现过程∠(°ゝ°)!
import java.util.Arrays;
public class SortArrBack{
public static void main(String[] args) {
Integer[] arr = {5,2,0,1,3,1,4};
Arrays.sort(arr, new Comparator<Integer>(){
@Override
// 这里对Comparator类中的compare方法进行了重写,使其降序
public int compare(Integer o1, Integer o2){
return o2-o1;
}
});
for (int e:arr) {
System.out.print(e);
}
}
}
在这里记录下sort的实现原理,赶趟可以跳往下一小节!下面就按照我的理解开始拉:
在compare(Integer o1, Integer o2)
方法中,o1 - o2 的返回值大小决定了元素的排序顺序:
- 如果返回负值,表示
o1
应排在o2
之前;- 如果返回0,表示两者相等,顺序不变;
- 如果返回正值,表示
o1
应排在o2
之后;
也就是说,o1-o2<0 时,o1在前(这就符合升序的含义,较小的数放在前);o1-o2>0时,也就是o1>o2,因此o2在前。知道了排序内部的原理后,如果要得到降序排列,那就可以把返回值改写成o2-o1,并且判断的条件不变(这其实就相当于给原来的比较方式加了一个负号)。
2.4 数组复制
copyOf(arr, int newlength)
// arr为要进行复制的数组
// newlength为复制后的新数组的长度
// 示例
int[] arr = new int[] {5,2,0,1,3,1,4};
int[] newarr = Arrays.copyOf(arr, 5);
// 输出为5,2,0,1,3
除了 newlength < arr.length的情况外,还有前者大于后者的情况:
// 示例1
int[] arr = new int[] {5,2,0,1,3,1,4};
int[] newarr = Arrays.copyOf(arr, 9);
// newarr为{5,2,0,1,3,1,4,0,0}
// 示例2
char[] ch = new char[] {'a', 'b', 'c', 'd'};
char[] newch = Arrays.copyOf(ch, 6);
// newch为{'a','b','c','d',null,null}
可以看出,char与int类型的填充值,分别是null和0。除了copyOf方法外,如果我只是想截取一段进行复制要怎么办,Arrays提供了copyOfRange()方法,和2.2节中提到的填充替换的方法类似,但又有点区别,这里主要记录下差异点:
int[] arr = new int[] {5,2,0,1,3,1,4};
int[] newarr = Arrays.copyOfRange(arr, 4, 10);
// newarr为{1,3,1,4,0,0}
2.5 数组查询
如果正常能够搜到元素,则返回元素在数组中的下标。这里主要记录下特殊情况,若在范围内没有搜索到的情况的返回值如何计算?
int[] arr = {1,8,9,30};
Array.sort(arr); // 二分查询前要先对数组排序
int a = Arrays.binarySearch(arr, 6);
// 此时a=-2
直观起见,这里直接创建的arr就是排序好的。在arr中显然搜索不到元素6,那么返回值的计算方法为,该元素应该插入的位置的负值再减一。
-(insertionPoint + 1)
注意:insertionPoint 指的是可以插入元素以保持数组有序的位置,并且这里的数组,指的是纳入搜索范围的数组。
元素6应该插入在1,8之间,也就是下标1的位置,所以最终返回值为-(1+1) = -2。这是对整体数组进行查询的情况,还有一种按照指定范围查询的,稍复杂的情况。
int[] arr = {1,7,8,9,30};
Array.sort(arr); // 二分查询前要先对数组排序
int a = Arrays.binarySearch(arr, 2, 4, 6);
// 此时a=-3
可能会有点疑惑,“6在数组中应该插入的下标位置不是1嘛,那按照上面的计算公式得到的结果不应该是-2嘛,为什么是-3呐?”
显然在arr数组中下标为2-4的元素上找不到6,而这里的情况特殊在,搜索的下标局部范围是2-4,而这个范围中最小的是8。那么要搜索的元素6应该放在元素8前面,以保持搜索范围内数组的有序性。而元素8此刻的下标是2,因此元素6应该插入的位置是2。再代入上述的公式,计算得到的结果就是-3!(不知道我说明白没有,如有问题欢迎在评论区交流!
对了,如果在实际操作的时候发现算不对,记得回头看看有没有对原数组进行排序,这个是前提!
参考资料:
《Java从入门到精通(第3版)》