8. 数组

空~2022年7月6日
  • java
大约 28 分钟

8. 数组

数组是编程语言中最常见的一种数据结构,可用于存储多个数据,每个数组元素存放一个数据,通常可通过数组元素的索引来访问数组元素,包括为数组元素赋值和取出数组元素的值。Java 语言的数组则具有其特有的特征,下面将详细介绍 Java 语言的数组。

理解数组

Java 的数组要求所有的数组元素具有相同的数据类型。因此,在一个数组中,数组元素的类型是唯一的,即一个数组里只能存储一种数据类型的数据,而不能存储多种数据类型的数据。

提示

因为 Java 语言是面向对象的语言,而类与类之间可以支持继承关系,这样可能产生一个数组里可以存放多种数据类型的假象。例如有一个水果数组,要求每个数组元素都是水果,实际上数组元素既可以是苹果,也可以是香蕉,但这个数组的数组元素的类型还是唯一的,只能是水果类型。

一旦数组的初始化完成,数组在内存中所占的空间将被固定下来,因此数组的长度将不可改变。即使把某个数组元素的数据清空,但它所占的空间依然被保留,依然属于该数组,数组的长度依然不变。

Java 的数组既可以存储基本类型的数据,也可以存储引用类型的数据,只要所有的数组元素具有相同的类型即可。

数组本身是一种引用类型。例如 int 是一个基本类型,但 int[] (这是定义数组的一种方式)就是一种引用类型了。

定义数组

Java 语言支持两种语法格式来定义数组:

type[] arrayName;
type arrayName[];

对这两种语法格式而言,通常推荐使用第一种格式。因为第一种格式不仅具有更好的语意,而且具有更好的可读性。

相关信息

C# 就不再支持 type arrayName[] 这种语法,它只支持第一种定义数组的语法。越来越多的语言不再支持 type arrayName[] 这种数组定义语法。

数组是一种引用类型的变量,因此使用它定义一个变量时,仅仅表示定义了一个引用变量(也就是定义了一个指针),这个引用变量还未指向任何有效的内存,因此定义数组时不能指定数组的长度。

而且由于定义数组只是定义了一个引用变量,并未指向任何有效的内存空间,所以还没有内存空间来存储数组元素,因此这个数组也不能使用,只有对数组进行初始化后才可以使用。

提示

定义数组时不能指定数组的长度。

数组的初始化

Java 语言中数组必须先初始化,然后才可以使用。所谓初始化,就是为数组的数组元素分配内存空间,并为每个数组元素赋初始值。

提示

一旦为数组的每个数组元素分配了内存空间,每个内存空间里存储的内容就是该数组元素的值,即使这个内存空间存储的内容是空,这个空也是一个值(null)。

不管以哪种方式来初始化数组,只要为数组元素分配了内存空间,数组元素就具有了初始值。初始值的获得有两种形式:一种由系统自动分配,另一种由程序员指定。

数组的初始化有如下两种方式。

静态初始化:初始化时由程序员显式指定每个数组元素的初始值,由系统决定数组长度。

动态初始化:初始化时程序员只指定数组长度,由系统为数组元素分配初始值。

静态初始化

静态初始化的语法格式如下:

type[] arrayName = new type[]{element1, element2, element3...};

前面的 type 就是数组元素的数据类型,此处的 type 必须与定义数组变量时所使用的 type 相同,也可以是定义数组时所指定的 type 的子类,并使用花括号把所有的数组元素括起来,多个数组元素之间以英文逗号 , 隔开,定义初始化值的花括号紧跟[]之后。

值得指出的是,执行静态初始化时,显式指定的数组元素值的类型必须与 new 关键字后的 type 类型相同,或者是其子类的实例。

// 定义一个int数组类型的变量,变量名为intArr
int[] intArr;
// 使用静态初始化,初始化数组时只指定数组元素的初始值,不指定数组长度
intArr = new int[] {5, 6, 8, 20};
// 定义一个Object数组类型的变量,变量名为objArr
Object[] objArr;
// 使用静态初始化,初始化数组时数组元素的类型是
// 定义数组时数组元素类型的子类
objArr = new String[] {"Java", "李刚"};
Object[] objArr2;
// 使用静态初始化
objArr2 = new Object[] {"Java", "李刚"};

因为 Java 语言是面向对象的编程语言,能很好地支持子类和父类的继承关系:子类实例是一种特殊的父类实例。在上面程序中,String 类型是 Object 类型的子类,即字符串是一种特殊的 Object 实例。

除此之外,静态初始化还有如下简化的语法格式:

type[] arrayName = {element1, element2, element3...};

在这种语法格式中,直接使用花括号来定义一个数组,花括号把所有的数组元素括起来形成一个数组。

在实际开发过程中,可能更习惯将数组定义和数组初始化同时完成。

int[] arr = {1, 2, 3};

动态初始化

动态初始化只指定数组的长度,由系统为每个数组元素指定初始值。动态初始化的语法格式如下:

type[] arrayName = new type[length];

在上面语法中,需要指定一个 int 类型的 length 参数,这个参数指定了数组的长度,也就是可以容纳数组元素的个数。

与静态初始化相似的是,此处的 type 必须与定义数组时使用的 type 类型相同,或者是定义数组时使用的 type 类型的子类。

// 数组的定义和初始化同时完成,使用动态初始化语法
int[] prices = new int[5];
// 数组的定义和初始化同时完成,初始化数组时元素的类型是定义数组时元素类型的子类
Object[] books = new String[4];

执行动态初始化时,程序员只需指定数组的长度,即为每个数组元素指定所需的内存空间,系统将负责为这些数组元素分配初始值。

指定初始值时,系统按如下规则分配初始值。

  1. 数组元素的类型是基本类型中的整数类型(byte、short、int 和 long),则数组元素的值是 0。
  2. 数组元素的类型是基本类型中的浮点类型(float、double),则数组元素的值是 0.0。
  3. 数组元素的类型是基本类型中的字符类型(char),则数组元素的值是'\u0000'。
  4. 数组元素的类型是基本类型中的布尔类型(boolean),则数组元素的值是 false。
  5. 数组元素的类型是引用类型(类、接口和数组),则数组元素的值是 null。

注意

不要同时使用静态初始化和动态初始化,也就是说,不要在进行数组初始化时,既指定数组的长度,也为每个数组元素分配初始值。

使用数组

数组最常用的用法就是访问数组元素,包括对数组元素进行赋值和取出数组元素的值。

访问数组元素都是通过在数组引用变量后紧跟一个方括号 [],方括号里是数组元素的索引值,这样就可以访问数组元素了。

访问到数组元素后,就可以把一个数组元素当成一个普通变量使用了,包括为该变量赋值和取出该变量的值,这个变量的类型就是定义数组时使用的类型。

Java 语言的数组索引是从 0 开始的,也就是说,第一个数组元素的索引值为 0,最后一个数组元素的索引值为数组长度减 1。

// 输出objArr数组的第二个元素,将输出字符串"李刚"
System.out.println(objArr[1]);
// 为objArr2的第一个数组元素赋值
objArr2[0] = "Spring";

如果访问数组元素时指定的索引值小于 0,或者大于等于数组的长度,编译程序不会出现任何错误,但运行时出现异常:java.lang.ArrayIndexOutOfBoundsException: N(数组索引越界异常),异常信息后的 N 就是程序员试图访问的数组索引。

相关信息

为什么要记住这些异常信息?

编写一个程序,并不是单单指在电脑里敲出这些代码,还包括调试这个程序,使之可以正常运行。

没有任何人可以保证自己写的程序总是正确的,因此调试程序是写程序的重要组成部分,调试程序的工作量往往超过编写代码的工作量。

如何根据错误提示信息,准确定位错误位置,并排除程序错误是程序员的基本功。培养这些基本功需要记住常见的异常信息,以及对应的出错原因。

所有的数组都提供了一个 length 属性,通过这个属性可以访问到数组的长度,一旦获得了数组的长度,就可以通过循环来遍历该数组的每个数组元素。

// 使用循环输出prices数组的每个数组元素的值
for (int i = 0; i < prices.length; i++) {
    System.out.println(prices[i]);
}

动态初始化的数组元素进行赋值,并通过循环方式输出每个数组元素。

// 对动态初始化后的数组元素进行赋值
books[0] = "疯狂Java讲义";
books[1] = "轻量级Java EE企业应用实战";
// 使用循环输出books数组的每个数组元素的值
for (int i = 0; i < books.length; i++) {
    System.out.println(books[i]);
}

初始化一个数组后,相当于同时初始化了多个相同类型的变量,通过数组元素的索引就可以自由访问这些变量(实际上都是数组元素)。

使用数组元素与使用普通变量并没有什么不同,一样可以对数组元素进行赋值,或者取出数组元素的值。

foreach 循环

使用 foreach 循环遍历数组和集合元素时,无须获得数组和集合长度,无须根据索引来访问数组元素和集合元素,foreach 循环自动遍历数组和集合的每个元素。

foreach 循环的语法格式如下:

for(type variableName : array | collection) {
    //variableName自动迭代访问每个元素..
}

在上面语法格式在中,type 是数组元素或集合元素的类型,variableName 是一个形参名,foreach 循环将自动将数组元素、集合元素依次赋给该变量。

public class ForEachTest {
    public static void main(String[] args) {
        String[] books = {"轻量级Java EE企业应用实战", "疯狂Java讲义", "疯狂Android讲义"};
        // 使用foreach循环来遍历数组元素//其中book将会自动迭代每个数组元素
        for (String book : books) {
            System.out.println(book);
        }
    }
}

使用 foreach 循环遍历数组元素时无须获得数组长度,也无须根据索引来访问数组元素。foreach 循环和普通循环不同的是,它无须循环条件,无须循环迭代语句,这些部分都由系统来完成,foreach 循环自动迭代数组的每个元素,当每个元素都被迭代一次后,foreach 循环自动结束。

当使用 foreach 循环来迭代输出数组元素或集合元素时,通常不要对循环变量进行赋值,虽然这种赋值在语法上是允许的,但没有太大的实际意义,而且极易引起错误。

public class ForEachErrorTest {
    public static void main(String[] args) {
        String[] books = {"轻量级Java EE企业应用实战", "疯狂Java讲义", "疯狂Android讲义"};
        // 使用foreach循环来遍历数组元素,其中book将会自动迭代每个数组元素
        for (String book : books) {
            book = "疯狂Ajax讲义";
            System.out.println(book);
        }
        System.out.println(books[0]);
    }
}

由于我们在 foreach 循环中对数组元素进行赋值,结果导致不能正确遍历数组元素,不能正确地取出每个数组元素的值。而且当再次访问第一个数组元素时,发现数组元素的值依然没有改变。

不难看出,当使用 foreach 来迭代访问数组元素时,foreach 中的循环变量相当于一个临时变量,系统会把数组元素依次赋给这个临时变量,而这个临时变量并不是数组元素,它只是保存了数组元素的值。

因此,如果希望改变数组元素的值,则不能使用这种 foreach 循环。

深入数组

数组是一种引用数据类型,数组引用变量只是一个引用,数组元素和数组变量在内存里是分开存放的。

内存中的数组

数组引用变量只是一个引用,这个引用变量可以指向任何有效的内存,只有当该引用指向有效内存后,才可通过该数组变量来访问数组元素。

与所有引用变量相同的是,引用变量是访问真实对象的根本方式。也就是说,如果我们希望在程序中访问数组对象本身,则只能通过这个数组的引用变量来访问它。

实际的数组对象被存储在堆(heap)内存中;如果引用该数组对象的数组引用变量是一个局部变量,那么它被存储在栈(stack)内存中。

img

如果需要访问如图所示堆内存中的数组元素,则程序中只能通过 p[index] 的形式实现。也就是说,数组引用变量是访问堆内存中数组元素的根本方式。

相关信息

为什么有栈内存和堆内存之分?

当一个方法执行时,每个方法都会建立自己的内存栈,在这个方法内定义的变量将会逐个放入这块栈内存里,随着方法的执行结束,这个方法的内存栈也将自然销毁。

因此,所有在方法中定义的局部变量都是放在栈内存中的;当我们在程序中创建一个对象时,这个对象将被保存到运行时数据区中,以便反复利用(因为对象的创建成本通常较大),这个运行时数据区就是堆内存。

堆内存中的对象不会随方法的结束而销毁,即使方法结束后,这个对象还可能被另一个引用变量所引用(在方法的参数传递时很常见),则这个对象依然不会被销毁。

只有当一个对象没有任何引用变量引用它时,系统的垃圾回收器才会在合适的时候回收它。

如果堆内存中数组不再有任何引用变量指向自己,则这个数组将成为垃圾,该数组所占的内存将会被系统的垃圾回收机制回收。

因此,为了让垃圾回收机制回收一个数组所占的内存空间,可以将该数组变量赋为 null,也就切断了数组引用变量和实际数组之间的引用关系,实际的数组也就成了垃圾。

只要类型相互兼容,就可以让一个数组变量指向另一个实际的数组,这种操作会让人产生数组的长度可变的错觉。

public class ArrayInRam {
    public static void main(String[] args) {
        // 定义并初始化数组,使用静态初始化
        int[] a = {5, 7, 20};
        // 定义并初始化数组,使用动态初始化
        int[] b = new int[4];
        // 输出b数组的长度
        System.out.println("b数组的长度为:" + b.length);
        // 循环输出a数组的元素
        for (int i = 0, len = a.length; i < len; i++) {
            System.out.println(a[i]);
        }
        // 循环输出b数组的元素
        for (int i = 0, len = b.length; i < len; i++) {
            System.out.println(b[i]);
        }
        // 因为a是int[]类型,b也是int[类型,所以可以将a的值赋给b。
        // 也就是让b引用指向a引用指向的数组
        b = a;
        // 再次输出b数组的长度
        System.out.println("b数组的长度为:" + b.length);
        // 4
    }
}

运行上面代码后,将可以看到先输出 b 数组的长度为 4,然后依次输出 a 数组和 b 数组的每个数组元素,接着会输出 b 数组的长度为 3。

看起来似乎数组的长度是可变的,但这只是一个假象。必须牢记:定义并初始化一个数组后,在内存中分配了两个空间,一个用于存放数组的引用变量,另一个用于存放数组本身。

当程序定义并初始化了 a、b 两个数组后,系统内存中实际上产生了 4 块内存区,其中栈内存中有两个引用变量:a 和 b;堆内存中也有两块内存区,分别用于存储 a 和 b 引用所指向的数组本身。

img

当执行上面的代码 b=a; 时,系统将会把 a 的值赋给 b,a 和 b 都是引用类型变量,存储的是地址。因此把 a 的值赋给 b 后,就是让 b 指向 a 所指向的地址。

img

当执行了 b=a; 之后,堆内存中的第一个数组具有了两个引用:a 变量和 b 变量都引用了第一个数组。此时第二个数组失去了引用,变成垃圾,只有等待垃圾回收机制来回收它——但它的长度依然不会改变,直到它彻底消失。

基本类型数组的初始化

对于基本类型数组而言,数组元素的值直接存储在对应的数组元素中,因此,初始化数组时,先为该数组分配内存空间,然后直接将数组元素的值存入对应数组元素中。

public class PrimitiveArrayTest {
    public static void main(String[] args) {
        // 定义一个int[]类型的数组变量
        int[] iArr;
        // 动态初始化数组,数组长度为5
        iArr = new int[5];
        // 采用循环方式为每个数组元素赋值
        for (int i = 0; i < iArr.length; i++) {
            iArr[i] = i + 10;
        }
    }
}

执行第一行代码 int[] iArr; 时,仅定义一个数组变量,此时内存中的存储示意图如图。

img

执行了 int[] iArr; 代码后,仅在栈内存中定义了一个空引用(就是 iArr 数组变量),这个引用并未指向任何有效的内存,当然无法指定数组的长度。

当执行 iArr=new int[5]; 动态初始化后,系统将负责为该数组分配内存空间,并分配默认的初始值:所有数组元素都被赋值为 0。

img

此时 iArr 数组的每个数组元素的值都是 0,当循环为该数组的每个数组元素依次赋值后,此时每个数组元素的值都变成程序显式指定的值。

img

引用类型数组的初始化

引用类型数组的数组元素是引用,因此情况变得更加复杂。每个数组元素里存储的还是引用,它指向另一块内存,这块内存里存储了有效数据。

定义一个 Person 类:

class Person {
    // 年龄
    public int age;
    // 身高
    public double height;

    // 定义一个info方法
    public void info() {
        System.out.println("我的年龄是:" + age + ",我的身高是:" + height);
    }
}

定义一个 Person[] 数组,接着动态初始化这个 Person[] 数组,并为这个数组的每个数组元素指定值。

public class ReferenceArrayTest {
    public static void main(String[] args) {
        // 定义一个students数组变量,其类型是Person[]
        Person[] students;
        // 执行动态初始化
        students = new Person[2];
        // 创建一个Person实例,并将这个Person实例赋给zhang变量
        Person zhang = new Person();
        // 为zhang所引用的Person对象的age、height赋值
        zhang.age = 15;
        zhang.height = 158;
        // 创建一个Person实例,并将这个Person实例赋给lee变量
        Person lee = new Person();
        // 为lee所引用的Person对象的age、height赋值
        lee.age = 16;
        lee.height = 161;
        // 将zhang变量的值赋给第一个数组元素
        students[0] = zhang;
        // 将lee变量的值赋给第二个数组元素
        students[1] = lee;
        // 下面两行代码的结果完全一样,因为lee
        // 和students[1]指向的是同一个Person实例
        lee.info();
        students[1].info();
    }
}

执行 Person[] students; 代码时,这行代码仅仅在栈内存中定义了一个引用变量,也就是一个指针,这个指针并未指向任何有效的内存区。

img

栈内存中定义了一个 students 变量,它仅仅是一个引用,并未指向任何有效的内存。

直到执行初始化,本程序对 students 数组执行动态初始化,动态初始化由系统为数组元素分配默认的初始值:null,即每个数组元素的值都是 null。

students 数组的两个数组元素都是引用,而且这个引用并未指向任何有效的内存,因此每个数组元素的值都是 null。

这意味着依然不能直接使用 students 数组元素,因为每个数组元素都是 null,这相当于定义了两个连续的 Person 变量,但这个变量还未指向任何有效的内存区,所以这两个连续的 Person 变量(students 数组的数组元素)还不能使用。

img

接着的代码定义了 zhanglee 两个 Person 实例,定义这两个实例实际上分配了 4 块内存,在栈内存中存储了 zhanglee 两个引用变量,还在堆内存中存储了两个 Person 实例。

img

此时 students 数组的两个数组元素依然是 null,直到程序依次将 zhang 赋给 students 数组的第一个元素,把 lee 赋给 students 数组的第二个元素,students 数组的两个数组元素将会指向有效的内存区。

img

此时 zhangstudents[0] 指向同一个内存区,而且它们都是引用类型变量,因此通过 zhangstudents[0] 来访问 Person 实例的 Field 和方法的效果完全一样,不论修改 students[0] 所指向的 Person 实例的 Field,还是修改 zhang 变量所指向的 Person 实例的 Field,所修改的其实是同一个内存区,所以必然互相影响。

同理,leestudents[1] 也是引用同一个 Person 对象,也具有相同的效果。

多维数组

Java 语言里的数组类型是引用类型,因此,数组变量其实是一个引用,这个引用指向真实的数组内存。

数组元素的类型也可以是引用,如果数组元素的引用再次指向真实的数组内存,这种情形看上去很像多维数组。

但如果从数组底层的运行机制上来看,没有多维数组。

回到前面定义数组类型的语法:type[] arrName;,这是典型的一维数组的定义语法,其中 type 是数组元素的类型。如果希望数组元素也是一个引用,而且是指向 int 数组的引用,则可以把 type 具体成 int[] ,那么上面定义数组的语法就是int[][] arrName

如果把 int 这个类型扩大到 Java 的所有类型(不包括数组类型),则出现了定义二维数组的语法:

type[][] arrName;

Java 语言采用上面的语法格式来定义二维数组,但它的实质还是一维数组,只是其数组元素也是引用,数组元素里保存的引用指向一维数组。

接着对这个“二维数组”执行初始化,同样可以把这个数组当成一维数组来初始化,把这个“二维数组”当成一个一维数组,其元素的类型是 type[] 类型,则可以采用如下语法进行初始化:

arrName = new type[length][];

上面的初始化语法相当于初始化了一个一维数组,这个一维数组的长度是 length。同样,因为这个一维数组的数组元素是引用类型(数组类型)的,所以系统为每个数组元素都分配初始值:null。

这个二维数组实际上完全可以当成一维数组使用:

使用 new type[length] 初始化一维数组后,相当于定义了 length 个 type 类型的变量;

使用 new type[length][] 初始化这个数组后,相当于定义了 length 个 type[] 类型的变量;

这些 type[] 类型的变量都是数组类型,因此必须再次初始化这些数组。

public class TwoDimensionTest {
    public static void main(String[] args) {
        // 定义一个二维数组
        int[][] a;
        // 把a当成一维数组进行初始化,初始化a是一个长度为4的数组
        // a数组的数组元素又是引用类型
        a = new int[4][];
        // 把a数组当成一维数组,遍历a数组的每个数组元素
        for (int i = 0, len = a.length; i < len; i++) {
            System.out.println(a[i]);
        }
        // 初始化a数组的第一个元素
        a[0] = new int[2];
        // 访问a数组的第一个元素所指数组的第二个元素
        a[0][1] = 6;
        // a数组的第一个元素是一个一维数组,遍历这个一维数组
        for (int i = 0, len = a[0].length; i < len; i++) {
            System.out.println(a[0][i]);
        }
    }
}

把 a 这个二维数组当成一维数组处理,只是每个数组元素都是 null,所以我们看到输出结果都是 null。

程序的第一行 int[][] a;,将在栈内存中定义一个引用变量,这个变量并未指向任何有效的内存空间,此时的堆内存中还未为这行代码分配任何存储区。

程序对 a 数组执行初始化:a = new int[4][];,这行代码让 a 变量指向一块长度为 4 的数组内存,这个长度为 4 的数组里每个数组元素都是引用类型(数组类型),系统为这些数组元素分配默认的初始值:null。

虽然声明 a 是一个二维数组,但这里丝毫看不出它是一个二维数组的样子,完全是一维数组的样子。

这个一维数组的长度是 4,只是这 4 个数组元素都是引用类型,它们的默认值是 null。

所以程序中可以把 a 数组当成一维数组处理,依次遍历 a 数组的每个元素,将看到每个数组元素的值都是 null。

img

因为 a 数组的元素必须是 int[] 数组,所以接下来的程序对 a[0] 元素执行初始化,右边堆内存中的第一个数组元素指向一个有效的数组内存,指向一个长度为 2 的 int 数组。

因为程序采用动态初始化 a[0] 数组,因此系统将为 a[0] 所引用数组的每个元素分配默认的初始值:0,然后程序显式为 a[0] 数组的第二个元素赋值为 6。

img

初始化多维数组时,可以只指定最左边维的大小;当然,也可以一次指定每一维的大小。

// 同时初始化二维数组的两个数
int[][] b = new int[3][4];

上面代码将定义一个 b 数组变量,这个数组变量指向一个长度为 3 的数组,这个数组的每个数组元素又是一个数组类型,它们各指向对应的长度为 4 的 int[] 数组,每个数组元素的值为 0。

img

还可以使用静态初始化方式来初始化二维数组。使用静态初始化方式来初始化二维数组时,二维数组的每个数组元素都是一维数组,因此必须指定多个一维数组作为二维数组的初始化值。

// 使用静态初始化语法来初始化一个二维数组
String[][] str1 = new String[][] {new String[3], new String[] {"hello"}};
// 使用简化的静态初始化语法来初始化二维数组
String[][] str2 = {new String[3], new String[] {"hello"}};

img

操作数组的工具类

Java 提供的 Arrays 类里包含的一些 static 修饰的方法可以直接操作数组,这个 Arrays 类里包含了如下几个 static 修饰的方法(static 修饰的方法可以直接通过类名调用)。

  1. int binarySearch(type[] a, type key):使用二分法查询 key 元素值在 a 数组中出现的索引;如果 a 数组不包含 key 元素值,则返回负数。调用该方法时要求数组中元素已经按升序排列,这样才能得到正确结果。
  2. int binarySearch(type[] a, int fromIndex, int toIndex, type key):这个方法与前一个方法类似,但它只搜索 a 数组中fromIndextoIndex索引的元素。调用该方法时要求数组中元素已经按升序排列,这样才能得到正确结果。
  3. type[] copyOf(type[] original, int newLength):这个方法将会把 original 数组复制成一个新数组,其中 length 是新数组的长度。如果 length 小于 original 数组的长度,则新数组就是原数组的前面 length 个元素;如果 length 大于 original 数组的长度,则新数组的前面元素就是原数组的所有元素,后面补充 0(数值类型)、false(布尔类型)或者 null(引用类型)。
  4. type[] copyOfRange(type[] original, int from, int to):这个方法与前面方法相似,但这个方法只复制 original 数组的 from 索引到 to 索引的元素。
  5. boolean equals(type[] a, type[] a2):如果 a 数组和 a2 数组的长度相等,而且 a 数组和 a2 数组的数组元素也一一相同,该方法将返回 true。
  6. void fill(type[] a, type val):该方法将会把 a 数组的所有元素都赋值为val
  7. void fill(type[] a, int fromIndex, int toIndex, type val):该方法与前一个方法的作用相同,区别只是该方法仅仅将 a 数组的fromIndextoIndex索引的数组元素赋值为val
  8. void sort(type[] a):该方法对 a 数组的数组元素进行排序。
  9. void sort(type[] a, int fromIndex, int toIndex):该方法与前一个方法相似,区别是该方法仅仅对fromIndextoIndex索引的元素进行排序。
  10. String toString(type[] a):该方法将一个数组转换成一个字符串。该方法按顺序把多个数组元素连缀在一起,多个数组元素使用英文逗号 , 和空格隔开。
public class ArraysTest {
    public static void main(String[] args) {
        // 定义一个a数组
        int[] a = new int[] {3, 4, 5, 6};
        // 定义一个a2数组
        int[] a2 = new int[] {3, 4, 5, 6};
        // a数组和a2数组的长度相等,每个元素依次相等,将输出true
        System.out.println("a数组和a2数组是否相等:" + Arrays.equals(a, a2));
        // 通过复制a数组,生成一个新的b数组
        int[] b = Arrays.copyOf(a, 6);
        System.out.println("a数组和b数组是否相等:" + Arrays.equals(a, b));
        // 输出b数组的元素,将输出[3,4,5,6,0,0]
        System.out.println("b数组的元素为:" + Arrays.toString(b));
        // 将b数组的第3个元素(包括)到第5个元素(不包括)赋值为1
        Arrays.fill(b, 2, 4, 1);
        // 输出b数组的元素,将输出[3,4,1,1,0,0]
        System.out.println("b数组的元素为︰" + Arrays.toString(b));
        // 对b数组进行排序
        Arrays.sort(b);
        // 输出b数组的元素,将输出[0,0,1,1,3,4]
        System.out.println("b数组的元素为:" + Arrays.toString(b));
    }
}

提示

Arrays 类处于 java.util 包下,为了在程序中使用 Arrays 类,必须在程序中导入java.util.Arrays