第十六章:数组

来源:互联网 发布:windows应用商店打不开 编辑:程序博客网 时间:2024/05/18 11:26

数组

  • 数组我相信大家都很熟悉吧。数组的优点就是随机读取速度快,像ArrayList就是使用了数组作为数据存储格式而实现的。但是缺点也很明显,它的大小是固定的。ArrayList之所以能够任意大小,是因为使用了size,扩容的时候拷贝数组到新数组。本章我们就来讨论一下数组的特点和用法。

数组是第一级对象

  • 无论使用哪种类型的数组,数组标识符其实只是一个引用,指向堆中创建的一个真实对象,这个(数组)对象用以保存指向其他对象的引用。除了new表达式显式创建数组对象,还可以用一些隐式语法。length是它的唯一一个可以访问的成员属性,并且是只读的。数组的类型既可以是引用类型,也可以是基本类型。如果是基本类型的话,都会有默认值。而引用类型则为null

多维数组

  • 我们这里来说一下粗糙数组。通常我们会这么定义多维数组:
    int[][] test = new int[5][5];
  • 这样相当于是定义了一个5*5的矩阵。但是如果说,我想定义一个不规则大小的数组怎么办?那么我们就可以这么写:
    int[][] test = new int[5][];    test[0] = new int[1];    test[1] = new int[2];    test[2] = new int[3];    test[3] = new int[4];    test[4] = new int[5];
  • java允许我们先确定最外层数组的大小,然后再逐步确定里层数组大小。这种写法比较少用,这里就做个笔记。

数组和泛型

  • 通常,数组与泛型不能很好的结合。你不能实例化具有参数化类型的数组:
List<String>[] ls = new List<String>[10];//编译错误
  • 但是我们可以通过一些人为控制来完成这个数组的创建。我们先来回忆一下泛型的使用。
public class People {    public static void main(String args[]) {        Holder<Integer> ho1 = new Holder<Integer>();        Holder<String> ho2 = new Holder<String>();        Holder ho11 = ho1;        Holder ho22 = ho2;        Holder<String> ho111 = ho11;        Holder<Integer> ho222 = ho22;        ho111.set(new String("1"));        ho222.set(new Integer(1));        System.out.println(ho111.get());        System.out.println(ho222.get());    }}class Holder <T> {    T obj;    T get() {        return obj;    }    void set(T obj) {        this.obj = obj;    }}----------------运行结果11
  • 你也许会以为new Holder<Integer>()new Holder<String>()是两种不同的类型。但是事实告诉我们,我们试图往前者插入String,不会导致任何错误。这是为什么呢?因为在Holder内部,它只认为泛型是它的擦除边界Object而已。而真正能够限制我们的是ho111认为的泛型类型(在编译期间)。我们当然不会这么写代码,此处也是为了让我们深刻的理解泛型的作用。再次强调,在泛型类内部,所有的泛型类型是擦除边界!
  • 那么此处我们应该就这样去定义这个数组:
List<String>[] ls = new List[10];
  • 你不要觉得new List[10];相比于new List<String>[10];有什么区别,他们本质是没有区别的,这个在上面已经讨论过了。只要我们List<String>[] ls这么做了,编译器就能够为我们有效检查ls元素的类型。虽然会有警告,但是大家可以放心的这么写。

Arrays实用功能

  • 先来讲一下Arrays.equals()Arrays.deepEquals()。前者是针对一维数组的,会比较其每个元素的equals()方法,后者是针对多维数组的。
import java.util.Arrays;public class People {    public static void main(String args[]) throws Exception {        int[] a = new int[10];        int[] b = new int[10];        //System.out.println(a.equals(b));//false 比较引用        System.out.println(Arrays.equals(a, b));//true        a[0] = 1;        System.out.println(Arrays.equals(a, b));//false        int[][] c = new int[1][];        int[][] d = new int[1][];        a = new int[1];        b = new int[1];        c[0] = a;        d[0] = a;        System.out.println(Arrays.equals(c, d));//true        System.out.println(Arrays.deepEquals(c, d));//true        d[0] = b;        System.out.println(Arrays.equals(c, d));//false        System.out.println(Arrays.deepEquals(c, d));//true        System.out.println();        c[0][0] = 1;        System.out.println(Arrays.equals(c, d));//false        System.out.println(Arrays.deepEquals(c, d));//false    }}
  • sort()是用于排序的,binarySearch()是对已经有序的数组进行二分法查询元素。toString()产生数组的字符串表示,fill()用于填充单一元素内容。还有其他用法就不过多介绍了。

复制数组

  • System.arraycopy()是一个用于复制(浅拷贝)数组的方法,它的速度比用循环复制要快得多。它需要的参数有:源数组,源数组偏移量,目标数组,目标数组偏移量,复制个数。另外需要注意的是该方法不会执行自动包装和自动拆包,两个数组必须具有相同的确切类型。来看下面的例子:
import java.lang.reflect.Field;import java.util.Arrays;public class People {    public static void main(String args[]) throws Exception {        int[] a = new int[10];        int[] b = new int[10];        Arrays.fill(a, 1);        Arrays.fill(a, 2);        System.out.println(Arrays.toString(a));        System.out.println(Arrays.toString(b));        //System.arraycopy(a, 5, b, 0, b.length);//a越界会产生异常,切记        //System.arraycopy(a, 0, b, 5, b.length);//b越界会产生异常,切记        System.arraycopy(a, 5, b, 5, b.length - 5);        System.out.println(Arrays.toString(b));        Integer[] c = new Integer[10];        Arrays.fill(c, new Integer(3));        System.out.println(Arrays.toString(c));        //System.arraycopy(a, 5, c, 5, c.length - 5);//不会自动包装和拆包,会产生异常,切记        Integer[] d = new Integer[10];        Arrays.fill(d, new Integer(4));        /*for (int i=0; i<d.length; i++) {            d[i] = new Integer(4);        }*///这种写法针对下面的浅拷贝测试只改变d[0]        System.arraycopy(d, 0, c, 5, d.length - 5);        System.out.println(Arrays.toString(c));        //为了验证是浅拷贝:        //接下来我打算用反射改变d[0]的值,当然也可以使用其他引用类型做测试,我这里就不改了        Field f = Integer.class.getDeclaredField("value");        f.setAccessible(true);        f.set(d[0], 520);//因为d[0]到d[9]其实是同一个对象,所以都会改变        System.out.println(Arrays.toString(d));        System.out.println(Arrays.toString(c));//c也变了,说明的确是浅拷贝        //更简单的判断方式:        System.out.println(new Integer(520) == new Integer(520));//false        System.out.println(d[0] == c[5]);//true    }}----------------------------运行结果[2, 2, 2, 2, 2, 2, 2, 2, 2, 2][0, 0, 0, 0, 0, 0, 0, 0, 0, 0][0, 0, 0, 0, 0, 2, 2, 2, 2, 2][3, 3, 3, 3, 3, 3, 3, 3, 3, 3][3, 3, 3, 3, 3, 4, 4, 4, 4, 4][520, 520, 520, 520, 520, 520, 520, 520, 520, 520][3, 3, 3, 3, 3, 520, 520, 520, 520, 520]

sort

  • Arrays.sort是一个很常用的方法,直接对int排序或者String排序,我相信大家都会,那如果我要对一个自定义的数组排序,该如何呢?此时我们需要使这个类实现Comparable接口,否则直接调用sort会出现CCE异常(因为其内部使用了Comparable接口的方法)。
import java.util.Arrays;import java.util.Comparator;public class People {    public static void main(String args[]) throws Exception {        Test[] test = new Test[5];        for (int i = 0; i < test.length; i++) {            test[i] = new Test(i, i + "" + i);        }        System.out.println(Arrays.toString(test));        Arrays.sort(test);        System.out.println(Arrays.toString(test));        // 假设我不满意这个排序方式,又无法直接修改Test类:        Arrays.sort(test, new Comparator<Test>() {            public int compare(Test o1, Test o2) {                //实际上String也实现了Comparable                return o1.s.compareTo(o2.s);            }        });        System.out.println(Arrays.toString(test));    }}class Test implements Comparable<Test> {    int i;    String s;    public Test(int i, String s) {        this.i = i;        this.s = s;    }    //Comparable 需要实现的方法    public int compareTo(Test o) {        return o.i - i;//逆序    }    //方便打印输出    public String toString() {        return i + "->" + s;    }}-------------------执行结果:[0->00, 1->11, 2->22, 3->33, 4->44][4->44, 3->33, 2->22, 1->11, 0->00][0->00, 1->11, 2->22, 3->33, 4->44]
原创粉丝点击