数组
数组:是一块连续的内存,存放相同的数据类型的集合
在java中,数组也叫作数组对象。
1.数组定义
int[] arr ={1,2,3};//静态初始化
int[] arr1=new int[10];//定义了数组,但未初始化,默认值为0
int[] arr2=new int[]{1,2,3};//动态初始化
- 引用不一定在栈上(局部->栈上),对象一定在堆上。
- 引用除了在定义时,在之后不能整体初始化。
2.数组的使用
1、数组打印:
import java.util.Arrays;
public class TestDemo {
public static void main(String[] args) {
int[] arr ={1,2,3};
int[] arr1=new int[10];
int[] arr2=new int[]{1,2,3,4};
//数组打印方式 1:
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
System.out.println();
for (int x:arr2) {
System.out.print(x+" ");
}
System.out.println();
//打印方式3
//将数组转化为字符串输出
String str = Arrays.toString(arr);
System.out.println(str);
}
}
//运行结果:
1 2 3
1 2 3 4
[1, 2, 3]
- 使用 arr.length 能够获取到数组的长度。 . 为成员访问操作符。
- 打印方式 1 可以拿到下标,方式 2 不可以。
- 方式3中的 Arrays 是一个工具类,专门用来操作数组的工具类。
- 使用 [ ] 按下标取(或修改)数组元素,需要注意, 下标从 0 开始计数。
- 下标访问操作不能超出有效范围 [0, length - 1] , 如果超出有效范围, 会出现下标越界异常。
2、下标越界:
int[] arr ={1,2,3};
System.out.println(arr[3]);
可以看到数组的长度为3,下标为0~2,输出arr[3],运行时会报错,数组下标访问异常。
3、认识 null:
- null 在 Java 中表示 "空引用"
- null 的作用类似于 C 语言中的 NULL (空指针), 都是表示一个无效的内存位置.。因此不能对这个内存进行任何读写操 作. 一旦尝试读写, 就会抛出 NullPointerException。
- arr = null, 代表arr不指向任何对象。
注意: Java 中并没有约定 null 和 0 号地址的内存有任何关联.
4、空指针异常:
当arr=null时,再去访问arr[ ]或者求取长度arr.length 时会报错,空指针异常。
int[] arr ={1,2,3};
arr =null;
System.out.println(arr.length);//运行报错:空指针异常
System.out.println(arr[2]);//运行报错:空指针异常
当代码运行时出现如上的空指针异常的报错,可以去检查引用是否等于null。
5、对象回收
int[] arr ={1,2,3};
arr =null;
当引用arr=null时,原对象{1,2,3}被回收;
当对象未被任何引用 引用时,这个对象就会被垃圾回收器回收掉。
6、引用不能指向引用,如出现以下,代表 引用arr1 指向了 引用arr 指向的对象。
int[ ] arr = {1,2,3};
int[ ] arr1= arr;
7、一个引用只能指向一个对象。如出现以下,最终只指向最后一个对象,之前两个没被其他引用 引用时就会被垃圾回收器回收了。
int[ ] arr = {1,2,3};
arr = new int[ ]{1,2};
arr = new int[ ]{1,2,3,4};
3.数组作为方法的参数
单独写一个方法打印数组。
public static void print(int[] a){
for (int i = 0; i <a.length; i++) {
System.out.print(a[i]+" ");
}
System.out.println();
}
public static void main(String[] args) {
int[] arr={1,2,3};
print(arr);
}
//运行结果:1 2 3
- 在这个代码中 int[] a 是函数的形参, int[ ] arr 是函数实参,如果需要获取到数组长度, 同样可以使用 a.length。
- 引用a 与arr都指向同一个对象,不管通过哪个引用修改对象的值,另一个引用去访问的时候也会受到影响。(例:如写一个方法swap()交换1,2。)
public class TestDemo {
public static void swap(int[] a){
int t=a[0];
a[0]=a[1];
a[1]=t;
}
public static void main(String[] args) {
int[] arr= {1,2};
System.out.println("交换前:arr[0]="+arr[0]+" arr[1]="+arr[1]);
swap(arr);
System.out.println("交换后:arr[0]="+arr[0]+" arr[1]="+arr[1]);
}
}
//运行结果:
交换前:arr[0]=1 arr[1]=2
交换后:arr[0]=2 arr[1]=1
4.数组作为返回值
例1:return可直接返回数组
import java.util.Arrays;
public class TestDemo {
public static int[] fun(){
int[] arr={1,2,3};
return arr;
//return new int[]{1,2,3}
//可替换上面两行,效果一致
//不可直接return {1,2,3}
}
public static void main(String[] args) {
int[] arr1=fun();
String str=Arrays.toString(arr1);
System.out.println(str);
}
}
//运行结果:[1, 2, 3]
例2: 写一个方法, 将数组中的每个元素都 * 2
public class TestDemo {
public static void main(String[] args) {
int[] arr = {1, 2, 3};
int[] arr1=transform(arr);
printArray(arr1);
}
public static void printArray(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
}
public static int[] transform(int[] arr) {
for (int i = 0; i < arr.length; i++) {
arr[i] = arr[i] * 2;
}
return arr;
}
}
//运行结果:2 4 6
- 这个代码固然可行, 但是破坏了原有数组.arr,有时候我们不希望破坏原数组, 就需要在方法transform内部创建一个新的数组( int[ ] ret = new int[arr.length] ), 并由 方法返回出来。另外由于数组是引用类型, 返回的时候只是将这个数组的首地址返回给函数调用者, 没有拷贝数组内容, 从而比较高效。
如下:
import java.util.Arrays;
public class TestDemo {
public static void main(String[] args) {
int[] arr = {1, 2, 3};
int[] arr1=transform(arr);
printArray(arr1);
}
public static int[] transform(int[] arr) {
int[] ret=new int[arr.length];
for (int i = 0; i < arr.length; i++) {
ret[i] = arr[i] * 2;
}
return ret;
}
public static void printArray(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
}
}
//运行结果:2 4 6
5.数组拷贝
方式1:循环拷贝
import java.util.Arrays;
public class TestDemo {
public static void main(String[] args) {
int[] arr={1,2,5,9,5,9,5,5,5};
int[] arr1=new int[arr.length];
for (int i = 0; i < arr.length; i++) {
arr1[i]=arr[i];
}
System.out.println("arr:"+Arrays.toString(arr));
System.out.println("arr1:"+Arrays.toString(arr1));
}
}
方式2:
Arrays.copyOf(原数组,拷贝长度)
import java.util.Arrays;
public class TestDemo {
public static void main(String[] args) {
int[] arr={1,2,5,9,5,9,5,5,5};
int[] arr1=Arrays.copyOf(arr,arr.length);
System.out.println("arr:"+Arrays.toString(arr));
System.out.println("arr1:"+Arrays.toString(arr1));
}
}
- 可实现部分拷贝
Arrays.copyOfRange(原始数组,起始位置,结束为止)//左闭右开式
import java.util.Arrays;
public class TestDemo {
public static void main(String[] args) {
int[] arr={1,2,5,9,5,9,5,5,5};
int[] arr1=Arrays.copyOfRange(arr,2,5);//左闭右开式,包含左边不包含右边
System.out.println("arr:"+Arrays.toString(arr));
System.out.println("arr1:"+Arrays.toString(arr1));
}
}
//运行结果:
arr:[1, 2, 5, 9, 5, 9, 5, 5, 5]
arr1:[5, 9, 5]
方式3:比方式2快
System.arraycopy(原来的数组,原来数组的位置,目的地的数组,目的地数组位置,拷贝长度);
import java.util.Arrays;
public class TestDemo {
public static void main(String[] args) {
int[] arr={1,2,5,9,5,9,5,5,5};
int[] arr1=new int[arr.length];
System.arraycopy(arr,0,arr1,0,arr.length);
System.out.println("arr:"+Arrays.toString(arr));
System.out.println("arr1:"+Arrays.toString(arr1));
}
}
方式4:
int[] arr1=arr.clone()
import java.util.Arrays;
public class TestDemo {
public static void main(String[] args) {
int[] arr={1,2,5,9,5,9,5,5,5};
int[] arr1=arr.clone();//产生当前引用的副本
System.out.println("arr:"+Arrays.toString(arr));
System.out.println("arr1:"+Arrays.toString(arr1));
}
}
这四种拷贝方式是深拷贝还是浅拷贝?
简单类型:深拷贝;引用类型:浅拷贝
拷贝后通过修改arr1(拷贝后的新数组)指向的对象,不会影响arr(原数组)所指向的对象,是深拷贝,反之。
6.二维数组
二维数组本质上也就是一维数组, 只不过每个元素又是一个一维数组
数据类型[ ][ ] 数组名称 = new 数据类型 [行数][列数] { 初始化数据 };
int[ ][ ] arr={{1,2,},{3,4}};( [ ][ ]什么都不能写 )
int[ ][ ] arr1= new int[2][3];//默认为0
int[ ][ ] arr2= new int[2][];//行不可以省略,列可以
int[ ][ ] arr3= new int[ ][ ]{{1,2,},{3,4}};( [ ][ ]什么都不能写 )
打印示例:(按需求选择)
打印1:
import java.util.Arrays;
public class TestDemo {
public static void main(String[] args) {
int[][] arr = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
for (int row = 0; row < arr.length; row++) {
for (int col = 0; col < arr[row].length; col++) {
System.out.printf("%d\t", arr[row][col]);
}
System.out.println("");
}
}
}
//运行结果
1 2 3 4
5 6 7 8
9 10 11 12
打印2:
import java.util.Arrays;
public class TestDemo {
public static void main(String[] args) {
int[][] arr = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
for(int[] arr1:arr){
for (int x : arr1) {
System.out.print(x+" ");
}
System.out.println();
}
}
}
打印3:
import java.util.Arrays;
public class TestDemo {
public static void main(String[] args) {
int[][] arr = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
String ret = Arrays.deepToString(arr);
System.out.println(ret);
}
}
//运行结果:[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]