7-Java 数组

7.1 数组的定义

数组是相同类型数据的有序集合。数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。其中,每一个数据称作一个元素,每个元素可以通过一个索引(下标)来访问它们。数组的三个基本特点:

  1. 长度是确定的。数组一旦被创建,它的大小就是不可以改变的。
  2. 其元素必须是相同类型,不允许出现混合类型。
  3. 数组类型可以是任何数据类型,包括基本类型和引用类型。

数组变量属引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量。数组本身就是对象,Java 中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中存储的。

7.2 数组声明

type[] arr_name; //(推荐使用这种方式)
type arr_name[];

注意:

  1. 声明的时候并没有实例化任何对象,只有在实例化数组对象时,JVM 才分配空间,这时才与长度有关。
  2. 声明一个数组的时候并没有数组真正被创建。
  3. 构造一个数组,必须指定长度。

创建基本类型一维数组

public class Test {
    public static void main(String args[]) {
        int[] s = null; // 声明数组;
        s = new int[10]; // 给数组分配空间;
        for (int i = 0; i < 10; i++) {
            s[i] = 2 * i + 1; // 给数组元素赋值;
            System.out.println(s[i]);
        } 
    }
} 

创建引用类型一维数组

class Man{
    private int age;
    private int id;
    public Man(int id,int age) {
        super();
        this.age = age;
        this.id = id;
    }
}
public class AppMain {
    public static void main(String[] args) {
        Man[] mans;  // 声明引用类型数组; 
        mans = new Man[10];  // 给引用类型数组分配空间;
         
        Man m1 = new Man(1,11);
        Man m2 = new Man(2,22);  
         
        mans[0]=m1; // 给引用类型数组元素赋值;
        mans[1]=m2; // 给引用类型数组元素赋值;
    }
}

7.3 初始化

数组的初始化方式总共有三种:静态初始化、动态初始化、默认初始化。下面针对这三种方式分别讲解。

1. 静态初始化

除了用 new 关键字来产生数组以外,还可以直接在定义数组的同时就为数组元素分配空间并赋值。

int[] a = { 1, 2, 3 }; // 静态初始化基本类型数组;
Man[] mans = { new Man(1, 1), new Man(2, 2) }; // 静态初始化引用类型数组;

2. 动态初始化

数组定义与为数组元素分配空间并赋值的操作分开进行。

int[] a1 = new int[2]; // 动态初始化数组,先分配空间;
a1[0]=1; // 给数组元素赋值;
a1[1]=2; // 给数组元素赋值;

3. 数组的默认初始化

数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化。

int a2[] = new int[2]; // 默认值:0,0
boolean[] b = new boolean[2]; // 默认值:false,false
String[] s = new String[2]; // 默认值:null, null

7.4 数组的遍历

数组元素下标的合法区间:[0, length-1]。我们可以通过下标来遍历数组中的元素,遍历时可以读取元素的值或者修改元素的值。

public class Test {
    public static void main(String[] args) {
        int[] a = new int[4];
        // 初始化数组元素的值
        for(int i = 0;i < a.length;i++){
            a[i] = 100 * i;
        }
        // 读取元素的值
        for(int i = 0;i < a.length;i++){
            System.out.println(a[i]);
        }
    }
}

7.5 for-each 循环

增强 for 循环 for-each 是 JDK1.5 新增加的功能,专门用于读取数组或集合中所有的元素,即对数组进行遍历。

public class Test {
    public static void main(String[] args) {
        String[] ss = {"aa", "bbb", "ccc", "ddd"};
        for (String temp : ss) {
            System.out.println(temp);
        }
    }
}

注意:

  1. for-each 增强 for 循环在遍历数组过程中不能修改数组中某元素的值。
  2. for-each 仅适用于遍历,不涉及有关索引(下标)的操作。

7.6 数组的拷贝

System 类里也包含了一个 static void arraycopy(object src,int srcpos,object dest, int destpos,int length) 方法,该方法可以将 src 数组里的元素值赋给 dest 数组的元素,其中 srcpos 指定从 src 数组的第几个元素开始赋值,length 参数指定将 src 数组的多少个元素赋给 dest 数组的元素。

public class Test {
    public static void main(String args[]) {
        String[] s = {"阿里", "百度", "京东", "搜狐", "网易"}; 
        String[] sBak = new String[6];
        System.arraycopy(s,0,sBak,0,s.length);
        for (int i = 0; i < sBak.length; i++) {
            System.out.print(sBak[i]+ "\t");
        }
    }
}

7.7 java.util.Arrays 类

JDK 提供的 java.util.Arrays 类,包含了常用的数组操作,方便我们日常开发。Arrays 类包含了:排序、查找、填充、打印内容等常见的操作。

打印

import java.util.Arrays;
public class Test {
    public static void main(String args[]) {
        int[] a = { 1, 2 };
        System.out.println(a); // 打印数组地址的值;
        System.out.println(Arrays.toString(a)); // 打印数组元素的值;
    }
}

排序

import java.util.Arrays;
public class Test {
    public static void main(String args[]) {
        int[] a = {1,2,323,23,543,12,59};
        System.out.println(Arrays.toString(a));
        Arrays.sort(a);
        System.out.println(Arrays.toString(a));
    }
}

引用类型的排序(Comparable 接口的应用)

import java.util.Arrays;
public class Test {
    public static void main(String[] args) {
        Man[] msMans = { new Man(3, "a"), new Man(60, "b"), new Man(2, "c") };
        Arrays.sort(msMans);
        System.out.println(Arrays.toString(msMans));
    }
}

class Man implements Comparable {
    int age;
    int id;
    String name;

    public Man(int age, String name) {
        super();
        this.age = age;
        this.name = name;
    }

    public String toString() {
        return this.name;
    }

    public int compareTo(Object o) {
        Man man = (Man) o;
        if (this.age < man.age) {
            return -1;
        }
        if (this.age > man.age) {
            return 1;
        }
        return 0;
    }
}

二分法查找

import java.util.Arrays;
public class Test {
    public static void main(String[] args) {
        int[] a = {1,2,323,23,543,12,59};
        System.out.println(Arrays.toString(a));
        Arrays.sort(a);   // 使用二分法查找,必须先对数组进行排序;
        System.out.println(Arrays.toString(a));
        // 返回排序后新的索引位置,若未找到返回负数。
        System.out.println("该元素的索引:"+Arrays.binarySearch(a, 12)); 
    }
}

数组填充

import java.util.Arrays;
public class Test {
    public static void main(String[] args) {
        int[] a= {1,2,323,23,543,12,59};
        System.out.println(Arrays.toString(a));
        Arrays.fill(a, 2, 4, 100);  // 将 2 到 4 索引的元素替换为 100;
        System.out.println(Arrays.toString(a));
    }
}

7.8 多维数组

多维数组可以看成以数组为元素的数组。可以有二维、三维、甚至更多维数组,但是实际开发中用的非常少。最多到二维数组(学习容器后,我们一般使用容器,二维数组用的都很少)。

二维数组的声明

public class Test {
    public static void main(String[] args) {
        // Java 中多维数组的声明和初始化应按从低维到高维的顺序进行
        int[][] a = new int[3][];
        a[0] = new int[2];
        a[1] = new int[4];
        a[2] = new int[3];
        // int a1[][]=new int[][4]; // 非法
    }
}

二维数组的静态初始化

public class Test {
    public static void main(String[] args) {
        int[][] a = { { 1, 2, 3 }, { 3, 4 }, { 3, 5, 6, 7 } };
        System.out.println(a[2][3]);
    }
}

二维数组的动态初始化

import java.util.Arrays;
public class Test {
    public static void main(String[] args) {
        int[][] a = new int[3][];
        // a[0] = {1,2,5}; // 错误,没有声明类型就初始化
        a[0] = new int[] { 1, 2 };
        a[1] = new int[] { 2, 2 };
        a[2] = new int[] { 2, 2, 3, 4 };
        System.out.println(a[2][3]);
        System.out.println(Arrays.toString(a[0]));
        System.out.println(Arrays.toString(a[1]));
        System.out.println(Arrays.toString(a[2]));
    }
}

获取数组长度

int[][] a = new int[3][4];
// 获取的二维数组第一维数组的长度。
System.out.println(a.length); // 3
// 获取第二维第一个数组长度。
System.out.println(a[0].length); // 4