16 数组 Arrays

对数组的基本看法是, 你可以创建并组装它们, 通过使用整型索引值访问它们的元素, 并且它们的尺寸不能改变

数组能在编译器检查具体类型, 来防止插入错误类型和抽取不当类型

数组相比于ArrayList, 仅存的优势就是效率, 这两者持有对象都是类型检查的

  • 数组对象

数组的标识符只是一个引用, 指向堆中创建的一个真实对象, 这个对象中存储的是指向其他对象的引用

只读成员length是数组对象的唯一成员, []语法是访问数组对象的唯一方式

X[] a; // 未初始化, 不能访问这个引用

X[]  b = new X[5]; // b指向一个数组对象, length是5, 表示数组中能够容纳的元素, 但不表示数组中实际保存的元素

                            // 所有的引用被自动初始化为null

                            // 如果引用不为null, 就表明这个位置存储了对象, 基本类型创建都有默认的初始值

X[] c = { new X(), new X() }; // {}里面写每一个对象的初始化, 写了几个length就是几, 必须在定义的位置使用

X[] d = new X[] { new X(), new X() }; // 和上面那个类似, 但是除了定义的位置, 也可以用在其他地方, 如方法传参数

a = d; //将指向某个数组对象的引用赋值给另一个数组对象

  • 返回一个数组

Java中可以直接返回数组, 和返回一个对象没什么不同

public static String[] f(int n) {

    String[] result = new String[n];

    return res;

}

  • 多维数组

int[][] a = {

    { 1, 1, 1, 1 },

    { 1, 1, 1, 1 }

};

多维数组用花括号把每个向量分开

Arrays.deepToString(Object);它可以将多维数组转化为多个String

int[][][] a = new int[2][2][4]; //可以用new来分配多维数组

多维数组必须至少确定第一维的长度, 其他维的可以空着, 当作不确定

这被称为粗糙数组

int[][][] a = new int[2][][];

a[0] = new int[3][];

a[0][0] = new int[5];

包装器对数组初始化器也起作用

Integer[][] a = {

    { 1, 2, 3, 4 },

    { 5, 6, 7 }

}

  •  数组与泛型

不能实例化参数化类型的数组

Peel<Banaa>[] peels = new Peel<Banana>[10];

但是可以创建它的引用

List<String>[] ls;

可以创建非泛型数组, 然后将其转型

List<String>[] ls;

List[] la = new ArrayList[];

ls = (List<String>[])la;

ls[0] = new ArrayList<String>();

Object[] objects = ls;

objects[1] = new ArrayList<Integer>();

不能创建泛型数组, 只能通过创建Object[], 再强制转型, 但Object[]在编译期和运行时, 都可以将任意类型对象塞进去

public ArrayOfGenericType(int size) {
        array = (T[])new Object[size];
}

  • 创建测试数据

fill方法

Arrays.fill(array, value);

Arrays.fill(array, start, end, value);

使用策咯设计模式, 选择Generator来创建数据

使用不同Generator来创建不同基本类型的计数器

static char[] chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
    public static class
    Character implements Generator<java.lang.Character> {
        int index = -1;
        public java.lang.Character next() {
            index = (index+1)%chars.length;
            return chars[index];
        }
    }

public static class
    String implements Generator<java.lang.String> {
        private int length = 7;
        Generator<java.lang.Character> cg = new Character();
        public String() {}
        public String(int length) { this.length = length; }
        public java.lang.String next() {
            char[] buf = new char[length];
            for(int i = 0;i < length;i++)
                buf[i] = cg.next();
            return new java.lang.String(buf);
        }
    }

可以测试生成器

public static test(Class<?> types) {

    for(Class<?> type : types) {

        try {

                Generator<?> g = (Generator<?>)type.newInstance();

                for(int i = 0;i < size;i++)

                    System.out.print(g.next() + " ");

       } catch(Exception e) {}

   }

}

用Generator填充数组, 产生Object子类型的数组

public static <T> T[] array(T[] a, Generator<T> gen) {
    return new CollectionData<T>(gen, a.length).toArray(a);
}
public static <T> T[] array(Class<T> type, Generator<T> gen, int size) {
    T[] a = (T[])java.lang.reflect.Array.newInstance(type, size);
    return new CollectionData<T>(gen, a.length).toArray(a);
}

CollectionData类可以创建一个由gen产生元素填充的Collection, 它带有一个toArray方法, 生成一个数组

这里可以创建包装器类型的数组, 还需要一个把包装器数组转化为基本类型数组的重载方法组

public static boolean[] primitive(Boolean in) {

    boolean[] result = new boolean[in.length];

    for(int i = 0;i < in.length;i++) 

        result[i] = in[i];

    return result;

}

这里自动包装机制, 转化为基本类型的数组

这两个方法组合起来用就可以产生基本类型数组了

boolean[] c = ConvertTo.primitive(
        Generated.array(Boolean.class, new CountingGenerator.Boolean(), 7)

);

  • 数组的实用方法

System.arraycopy(src, srcPos, dest, destPos, length);

拷贝数组1某位置到数组2某位置开始length个元素

如果拷贝的是对象数组, 拷贝的仅仅是引用, 而不是创建新的对象, 这被称为浅拷贝

Arrays.equals(a1, a2);

静态方法, 比较两个数组是否相等

相等的条件是两个数组的长度相等, 每个位置上的元素相等, 这可以通过每一个元素的equals来对比, 如果是基本类型

可以通过基本类型重载的诸如Integer.equals来对比, 像String也是, 只要求字符串内容相等, 不需要是同一个对象

数组元素的比较

实现java.lang.Comparable接口, 里面有一个compareTo方法, 可以定义比较的方式

class Comptype imlements Comarable<CompType> {

    int i;

    public Comptype(int i) { this.i = i; }

    public int compareTo(ComType rv) {

        return ( i < rv.i ? -1 : ( i == rv.i ? 0 : 1 ) );

    }

}

Arrays.sort(a);

Collections.reverseOrder()使得原来的排序效果反转

Arrays.sort(a, Collections.reverseOrder());

实现Comparator接口, 可以在sort的参数里面加上自己定义的比较方法

class CompTypeComparator implements Comparator<CompType> {
    public int compare(CompType o1, CompType o2) {
        return ( o1.j < o2.j  ? -1 : ( o1.j == o2.j ? 0 : 1));
    }
}

CompType[] a = Generated.array(
            new CompType[12], CompType.generator()
);

Arrays.sort(a, new CompTypeComparator());

这里按照j从小到大排序

Arrays.binarySearch(a, r);

在有序数组a里面找元素r的索引, 找不到应插入的位置

如果用Comparator排序了某个对象数组,  在binarySearch中则必须提供相同的Comparator

String[] sa = Generated.array(new String[30],
            new RandomGenerator.String(5));
        Arrays.sort(sa, String.CASE_INSENSITIVE_ORDER);
        System.out.println(Arrays.toString(sa));
        int index = Arrays.binarySearch(sa, sa[10], String.CASE_INSENSITIVE_ORDER);
        System.out.println(index + " " + sa[index]);

这里用了String的字典排序方法CASE_INSENSITIVE_ORDER, 二分查找的时候也加入了这个方法

 

创建数组初始化的时候, 创建的是1个对象, 即数组对象, 像这样 int[] a = new int[5];

它包含的唯一成员就是它的长度length, 所以不管几维数组, 都必须定义第一维的长度, 以产生一个数组对象, 而不是一个空引用

这个对象里面储存的是每一个元素所对应的引用(所以每一个元素的引用可以还没初始化为对象, 抑或也是数组对象)

数组强调的是性能而不是灵活性

应该优先使用容器而不是数组, 除非能证明性能成为问题

 

 

   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值