学习笔记之JavaSE(6)--Java基础语法5

时间:2023-02-16 22:26:38

今天学习的内容是数组和Arrays类


一、一维数组和Arrays类

数组是存放相同类型的一组数据的容器,它可以存储基本数据类型和对象。比较特殊的是:数组是对象。Arrays类属于Java核心类库java.util,它包含一套操作数组的静态方法。

数组和容器类都作为存放数据的容器,那它们有什么区别呢?数组和集合类的区别有三方面:效率类型安全保存基本类型的能力。随着泛型和自动打包机制的出现,集合类已经可以实现类型安全,并且也可以存储基本数据类型。目前数组的优势只剩下效率,但是为效率所付出的代价是数组对象的大小被固定,在其生命周期不能改变。除非证明性能成为问题,并且使用数组会对性能提高有所帮助,否则建议“优选集合而不是数组”。

那为什么我们要学习数组呢?当然是为了面试啦学习笔记之JavaSE(6)--Java基础语法5 当然一些常用算法的思想我们也是必须要了解的

定义一维数组的格式有三种:

  • 数组元素类型[] 数组名=new 数组元素类型[数组元素个数];数组名[0]=值;(可以不初始化,数组中的元素默认初始化)
  • 数组元素类型[] 数组名=new 数组元素类型[]{数组元素}; 注意:这种定义方法不能写数组元素个数
  • 数组元素类型[] 数组名={数组元素}  注意:这种定义方法虽然没用new,但是创建的数组也是对象

使用数组还需要注意:当访问数组不存在的下标,运行时会发生ArrayIndexOutOfBoundsException异常;当数组引用没有引用实体,还在用其操作实体,运行时会发生NullPointerException异常。不过这两种异常不会被编译器发现,它们属于运行时异常(Runtime Exception)。

定义一维数组、使用常规算法和Arrays类静态方法完成对一维数组的遍历排序等操作的示例代码如下:

<pre name="code" class="java">public class Test18 {

public static void main(String[] args){

//第一种定义格式:
int[] arr_1=new int[3];
arr_1[0]=1;
arr_1[1]=2;
arr_1[2]=3;
System.out.println(arr_1);//[I@304e94a4 对象类型+@+十六进制哈希值
System.out.println(arr_1.hashCode());//810456228 哈希值
System.out.println(Integer.toHexString(arr_1.hashCode()));//304e94a4 十六进制哈希值
System.out.println(Arrays.toString(arr_1));//使用Arrays类的toString静态覆盖方法将数组转为字符串格式,[1,2,3]

//第二种定义格式:
int[] arr_2=new int[]{4,5,6};
System.out.println(arr_2);//[I@7700b3c2 对象类型+@+十六进制哈希值
System.out.println(Arrays.hashCode(arr_2));//33796 哈希值
System.out.println(Arrays.toString(arr_2));//使用Arrays类的toString静态覆盖方法将数组转为字符串格式,[4,5,6]

//第三种定义格式:
int[] arr_3={7,8,9};
System.out.println(arr_3);//[I@4f19c297 对象类型+@+十六进制哈希值
System.out.println(Arrays.hashCode(arr_3));//36775 哈希值
System.out.println(Arrays.toString(arr_3));//使用Arrays类的toString静态覆盖方法将数组转为字符串格式,[7,8,9]


//数组常用操作1:遍历
System.out.print("使用for循环遍历一维数组:");
for(int i=0;i<arr_1.length;i++){
System.out.print(arr_1[i]+" ");//1 2 3
}
System.out.print("\n使用foreach循环遍历一维数组;");
for(int x:arr_1){
System.out.print(x+" ");//1 2 3
}


//数组常用操作2:获取最值
int[] arr_4={3,5,1,6,2,43,35,2,9};
//比较每个元素
int maxElement=arr_4[0];
for(int i=1;i<arr_4.length;i++){
maxElement=(maxElement>arr_4[i])?maxElement:arr_4[i];
}
System.out.println("\n数组最大值为"+maxElement);//43
int minElement=arr_4[0];
for(int i=1;i<arr_4.length;i++){
minElement=(minElement<arr_4[i])?minElement:arr_4[i];
}
System.out.println("数组最小值为"+minElement);//1
//通过下标比较每个元素
int maxIndex=0;
for(int i=1;i<arr_4.length;i++){
arr_4[maxIndex]=(arr_4[maxIndex]>arr_4[i])?arr_4[maxIndex]:arr_4[i];
}
System.out.println("数组最大值为"+arr_4[maxIndex]);//43
int minIndex=0;
for(int i=1;i<arr_4.length;i++){
arr_4[minIndex]=(arr_4[minIndex]<arr_4[i])?arr_4[minIndex]:arr_4[i];
}
System.out.println("数组最小值为"+arr_4[minIndex]);//1
//借用Arrays类的sort静态方法排序,然后获取最值
Arrays.sort(arr_4);
System.out.println("数组最大值为"+arr_4[arr_4.length-1]);//43
System.out.println("数组最小值为"+arr_4[0]);//1


//数组常用操作3:排序
int[] arr_5={3,5,6,4,2,1,8,9,7};
//使用Arrays的sort静态方法(实际开发使用)
Arrays.sort(arr_5);
System.out.println("使用Arrays静态方法排序的结果:"+Arrays.toString(arr_5));//[1-9]
//选择排序
for(int i=0;i<arr_5.length-1;i++){
for(int j=i+1;j<arr_5.length;j++){
if(arr_5[i]>arr_5[j]){
int temp=arr_5[i];
arr_5[i]=arr_5[j];
arr_5[j]=temp;
}
}
}
System.out.println("使用选择排序的结果:"+Arrays.toString(arr_5));//[1-9]
//冒泡排序(内循环-1:为了避免下标越界 内循环-i:为了每当外循环增加一次,内循环参与比较的元素个数就递减)
for(int i=0;i<arr_5.length-1;i++){
for(int j=0;j<arr_5.length-1-i;j++){
if(arr_5[j]>arr_5[j+1]){
int temp=arr_5[j];
arr_5[j]=arr_5[j+1];
arr_5[j+1]=temp;
}
}
}
System.out.println("使用冒泡排序的结果:"+Arrays.toString(arr_5));//[1-9]


//数组常用操作4:查找某元素的索引
int[] arr_6={3,1,4,65,7,1};
//遍历查找
for(int i=0;i<arr_6.length;i++){
if(arr_6[i]==1){
System.out.println("数字1在数组中的索引为:"+i);//1 5
}
}
//使用Arrays类的binarySearch静态方法,本质就是二分法
//使用此方法必须先对数组排序,如果数组未排序将产生不可预料的后果
//如果数组中有多个该值,则无法保证找到的是哪一个
//如果数组没有这个值,那么就会返回这个值在数组中按顺序应该存在的位置取负数再减一
//binarySearch方法还可以限定查找索引范围(第一个包括,第二个不包括)
Arrays.sort(arr_6);
System.out.println("数字3在数组中的索引为:"+Arrays.binarySearch(arr_6, 3));//2
System.out.println("数字1在数组中的索引为:"+Arrays.binarySearch(arr_6, 1));//0(实际上有0和1)
System.out.println("数字5在数组中的索引为:"+Arrays.binarySearch(arr_6, 5));//-5(-4-1)
System.out.println("数字1在数组中的索引为:"+Arrays.binarySearch(arr_6,0,1,1));//0


//数组常用操作5:填充替换数组元素
//使用Arrays的fill静态方法
//可以选择全部填充也可以设定填充范围(第一个包括,第二个不包括)
int[] arr_7={1,1,1};
Arrays.fill(arr_7, 2);
System.out.println(Arrays.toString(arr_7));//[2,2,2]
Arrays.fill(arr_7,0,2,3);
System.out.println(Arrays.toString(arr_7));//[3,3,2]


//数组常用操作6:复制数组
//使用Arrays的copyOf静态方法
//如果复制长度大于原数组长度,用该类型的默认值填充;如果复制长度小于原数组长度,就从数组的第一个元素开始截取
int[] arr_8={1,2,3,4};
System.out.println(Arrays.toString(Arrays.copyOf(arr_8, 2)));//[1,2]
System.out.println(Arrays.toString(Arrays.copyOf(arr_8, 5)));//[1,2,3,4,0]


//数组常用操作7:数组间的比较
//Arrays类的equals静态覆盖方法可以比较两个数组的内容(元素个数和元素对应内容)
int[] a={1,2,3};
int[] b={1,2,3};
int[] c=new int[]{1,2,3};
int[] d=new int[]{1,2,3};
System.out.println("==和equals的数组验证:");
System.out.println(a==b);//false
System.out.println(a.equals(b));//false
System.out.println(Arrays.equals(a, b));//true
System.out.println(c==d);//false
System.out.println(c.equals(d));//false
System.out.println(Arrays.equals(c, d));//true
}
}


 
细心的人,比如我,有一些疑问:1. 
哈希值和内存地址是什么?为什么使用两种方式得到的哈希值不同?2. 
为什么数组使用==和equals会得到false,而使用Arrays的equals方法又能得到true?3. 
引用类型和对象是什么?和基本数据类型有何不同? 
这些疑问将在之后的几篇文章中详细解答 

二、二维数组

说完了一维数组,二维数组就比较简单了,可以简单将其理解为表(Table)。与一维数组的不同主要就是定义格式和三个Arrays类针对多维数组操作的静态方法,直接看示例程序:

public class Test19 {

public static void main(String[] args){
//第一种定义格式
int[][] arr_1=new int[2][3];//数组所有元素有默认值0
System.out.println("使用for循环遍历二维数组:");
for(int i=0;i<arr_1.length;i++){
for(int j=0;j<arr_1[i].length;j++){
System.out.print(arr_1[i][j]+" ");
}
System.out.println();
}
System.out.println("使用foreach循环遍历二维数组;");
for(int[] x:arr_1){
for(int y:x){
System.out.print(y+" ");
}
System.out.println();
}
System.out.println(arr_1);//打印引用的值,对象类型+@+数组对象的内存地址
System.out.println(arr_1.hashCode());//哈希值,与上面的引用的值不同
System.out.println(Arrays.deepHashCode(arr_1));//哈希值,与上面的引用的值不同
System.out.println(arr_1[0]);//打印引用的值,对象类型+@+数组对象的内存地址
System.out.println(arr_1[1]);//打印引用的值,对象类型+@+数组对象的内存地址

//第二种定义格式
int[][] arr_2=new int[2][];
System.out.println(arr_2);//打印引用的值,对象类型+@+数组对象的内存地址(哈希值)
System.out.println(arr_2[0]);//null
System.out.println(arr_2[1]);//null
//!arr_2[0]={1,2,3};注意这是错误的!
arr_2[0]=new int[3];
arr_2[1]=new int[]{4,5,6};
System.out.println(Arrays.deepToString(arr_2));//打印多维数组的Arrays类的静态方法

//第三种定义格式
int[][] arr_3=new int[][]{{1,2,3},{4,5,6}};
//int[][] arr_3={{1,2,3},{4,5,6}};也是可以的
for(int i=0;i<arr_3.length;i++){
for(int j=0;j<arr_3[i].length;j++){
System.out.print(arr_3[i][j]+" ");
}
System.out.println();
}
System.out.println(arr_3);//打印引用的值,对象类型+@+数组对象的内存地址(哈希值)
System.out.println(arr_3[0]);//打印引用的值,对象类型+@+数组对象的内存地址(哈希值)
System.out.println(arr_3[1]);//打印引用的值,对象类型+@+数组对象的内存地址(哈希值)

//二维数组间的比较
int[][] arr_4={{1,2},{3,4}};
int[][] arr_5={{1,2},{3,4}};
int[][] arr_6=new int[][]{{1,2,3},{4,5,6}};
int[][] arr_7=new int[][]{{1,2,3},{4,5,6}};
System.out.println(arr_4==arr_5);//false
System.out.println(arr_4.equals(arr_5));//false
System.out.println(Arrays.deepEquals(arr_4, arr_5));//true
System.out.println(arr_6==arr_7);//false
System.out.println(arr_6.equals(arr_7));//false
System.out.println(Arrays.deepEquals(arr_6, arr_7));//true
}
}