Java编程思想—第16章 数组

  • 对数组的基本见解是,你能够建立并组装它们,经过使用整型索引值访问它们的元素,而且它们的尺寸不能改变

16.1 数组为何特殊

  1. 数组与其余种类的容器之间的区别有三方面:效率类型保存基本类型的能力
    a. 在Java中,数组是一种效率最高的存储和访问随机对象引用序列的方式
    b. 数组就是一个简单的线性序列,这使得元素访问很是快速
    c. 可是为这种速度所付出的代价是数组对象的大小被固定,而且在其生命周期中不可改变

16.2 数组是第一级对象

  1. 不管使用哪一种类型的数组,数组标识符其实只是一个引用,指向在堆中建立的一个真实对象,这个(数组)对象用以保存指向其余对象的引用。
  2. 只读成员length是数组对象的一部分(事实上,这是惟一一个能够访问的字段或方法),表示此数组对象能够存储多少元素
Integer[] a;
Integer[] b = new Integer[5];  //length是数组的大小,而不是实际保存的元素个数
a = new Integer[]{ 
 
  1,2,3,4};
a = { 
 
  1,2,3,4};

16.3 返回一个数组

  1. 在Java中,你只是直接“返回一个数组”,而无需担忧要为数组负责——只要你须要它,它就会一直存在,在你使用完后,垃圾回收器会清理掉它

16.4 多维数组

  1. 建立多位数组很方便。对于基本类型的多维数组,能够经过使用花括号将每一个向量分隔开
int[][] a = { 
 
  { 
 
  1,2,3}, { 
 
  4,5,6}}
int[][][] b = new int[2][2][4];
Arrays.deepToString(a);  //能够将多维数组转换成字符串打印
  1. 数组中构成矩阵的每一个向量均可以具备任意长度(这被称为粗糙数组)
  2. 自动包装机制对数组初始化器也起做用
  3. Arrays.deepToString()方法对基本类型数组和对象都起做用

16.5 数组与泛型

  1. 一般,数组和泛型不能很好的结合。你不能实例化具备参数化类型的数组
    a. 擦除会移除参数类型信息,而数组必须知道它们所持有的确切类型,以强制保证类型安全
  2. 你能够参数化数组自己的类型
class ClassParameter<T> { 
 
  
    public T[] f(T[] arg){ 
 
   return arg;}
}

class MethodParameter{ 
 
  
    public static <T> T[] f(T[] arg){ 
 
   return arg;}
}

public class ParameterizedArrayType{ 
 
  
    public static void main(String[] args){ 
 
  
        Integer[] ints = { 
 
  1, 2, 3, 4, 5};
        Double[] doubles = { 
 
  1.1, 2.2, 3.3, 4.4, 5.5};
        Integer[] ints2 = new ClassParameter<Integer>().f(ints);
        Double[] doubles2 = new ClassParameter<Double>().f(doubles);
        ints2 = MethodParameter.f(ints);
        doubles2 = MethodParameter.f(doubles);
    }
}
  1. 使用参数化方法而不使用参数化类的方便之处在于:你没必要为须要应用的每种不一样的类型都使用一个参数去实例化这个类,而且你能够将其定义为静态
  2. 尽管你不能建立实际的持有泛型的数组对象,可是你 能够建立非泛型的数组,而后将其转型
List<String>[] ls;
List[] la = New List[10];
ls = (List<String>[]) la;
ls[0] = new ArrayList<String>();

16.6 建立测试数据

  • 一般,在试验数组和程序时,可以很方便地生成填充了测试数据的数组,将会颇有帮助
  1. Arrays.fill()
    a. 只能用同一个值填充各个位置,而针对对象而言,就是复制同一个引用进行填充
char[] c = new char[3];
Arrays.fill(c, 'a');
Arrays.fill(c,1,3,'b');  //对某个区域进行填充
  1. 数据生成器
    a. 经过Generator的类型来建立任何类型的数据
  2. 从Generator中建立数组

16.7 Arrays实用功能

  1. 复制数组
    a. System.arraycopy(),用它复制数组比用for循环要快不少
    b. 参数:源数组,表示从源数组中的什么位置开始复制的偏移量,目标数组,表示从目标数组的什么位置开始复制的偏移量,以及须要复制的元素个数
    c. System.arraycopy()不会执行自动包装和在自动拆包,两个数组必须具备相同的确切类型
System.arraycopy(i,0,j,0,i.length);
  1. 数组的比较
    a. Arrays类提供了重载后的equals()方法
    b. 数组相等的条件是元素个数必须相等,而且对应位置的元素也相等
    c. 对于基本类型,须要使用基本类型的包装器类的equals()方法,例如,对于int类型使用Integer.equals()做比较
Arrays.equals(a1, a2);
  1. 数组元素的比较
    a. 排序必须根据对象的实际类型执行比较操做
    b. Java有两种方式来提供比较功能
    (1)第一种是java.lang.Comparable接口,使你的类具备“天生”的比较能力
    (2)能够实现Comparator接口,Collections类包含一个reverseOrder()方法,该方法能够产生一个Comparator,它能够反转天然的排序顺序
public class CompType implements Comparable<CompType>{ 
 
  
    int i;
    int j;
    public CompType(int n1, int n2){ 
 
  
        i = n1;
        j = n2;
    }
    
    public int comparaTo(CompType rv){ 
 
  
        return (i < rv.i ? -1 : (i == rv.i ? 0: 1)); //递增顺序
    }
}
  1. 数组排序
    a. 使用内置的排序方法,就能够对任意的基本类型数组排序;也能够对任意的数组对象进行排序,只要该对象实现了Comparable接口或具备相关联的Comparator
Arrays.sort(sa);
Arrays.sort(sa, Collections.reverseOrder());  //反序
Arrays.sort(sa, String.CASE_INSENSITIVE_ORDER);  //忽略大小写的字典排序
  1. 在已排序的数组中查找
    a. 若是数组已经排好序了,就能够使用Arrays.binarySearch()执行快速查找

16.8 总结

  1. 当你使用最近的Java版本编程时,应该“优先容器而不是数组”。只有在以证实性能成为问题(而且切换到数组对性能提升有所帮助)时,你才应该将程序重构为使用数组