16.1 數(shù)組為什么特殊
數(shù)組與其他種類的容器之間的區(qū)別有三方面:效率、類型和保存基本類型的能力。在java中,數(shù)組是一種效率最高的存儲和隨機訪問對象引用序列的方式。為這種速度所付出的代價就是數(shù)組對象的大小被固定,并且在其生命周期中不可改變。
數(shù)組之所以優(yōu)于泛型之前的容器,就是因為你可以創(chuàng)建一個數(shù)組去持有某種具體類型。這意味著你可以通過編譯器檢查,來放置插入錯誤類型和抽取不當類型。
隨著自動包裝機制的出現(xiàn),容器已經(jīng)可以與數(shù)組幾乎一樣方便地用于基本類型中了。數(shù)組碩果僅存的有點就是效率。
16.2 數(shù)組是第一級對象
基本類型的數(shù)組如果是數(shù)值型,就被自動初始化為0;如果是字符型,就被自動轉化為O;如果是布爾型,就被自動初始化為false。
16.3 返回一個數(shù)組
在java中,你只是直接“返回一個數(shù)組”,而無需擔心要為數(shù)組負責——只要你需要它,它就會一直存在,當你使用完后,垃圾回收器會清理掉它。
16.4 多維數(shù)組
Arrays.deepToString方法可以將多維數(shù)組轉換為多個String。
數(shù)組中構成矩陣的每個向量都可以具有任意的長度,這被稱為粗糙數(shù)組,其每個對象列表的長度都是不相等的。
public class RaggedArray {
public static void main(String[] args) {
Random rand = new Random(47);
// 3-D array with varied-length vectors:
int[][][] a = new int[rand.nextInt(7)][][];
for(int i = 0; i < a.length; i++) {
a[i] = new int[rand.nextInt(5)][];
for(int j = 0; j < a[i].length; j++)
a[i][j] = new int[rand.nextInt(5)];
}
System.out.println(Arrays.deepToString(a));
}
}
自動包裝機制對數(shù)組初始化也起作用。
16.5 數(shù)組與泛型
數(shù)組與泛型不能很好地組合,不能實例化具有參數(shù)化類型的數(shù)組。但是可以參數(shù)化數(shù)組本身的類型。
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);
}
}
使用參數(shù)化方法而不使用參數(shù)化類的方便之處在于:你不必為需要應用的每種不同的類型都使用一個參數(shù)去實例化這個類,并且你可以將其定義為靜態(tài)的。
盡管不能創(chuàng)建實際的持有泛型的數(shù)組對象,但是可以創(chuàng)建非泛型的數(shù)組,然后將其轉型:
public class ArrayOfGenerics {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
List<String>[] ls;
List[] la = new List[10];
ls = (List<String>[]) la; // "Unchecked" warning
ls[0] = new ArrayList<String>();
// Compile-time checking produces an error:
//! ls[1] = new ArrayList<Integer>();
// The problem: List<String> is a subtype of Object
Object[] objects = ls; // So assignment is OK
// Compiles and runs without complaint:
objects[1] = new ArrayList<Integer>();
// However, if your needs are straightforward it is
// possible to create an array of generics, albeit
// with an "unchecked" warning:
List<BerylliumSphere>[] spheres =
(List<BerylliumSphere>[]) new List[10];
for (int i = 0; i < spheres.length; i++)
spheres[i] = new ArrayList<BerylliumSphere>();
}
}
16.6 創(chuàng)建測試數(shù)據(jù)
Arrays.fill()方法,只能用同一個值填充各個位置,而針對對象而言,就是復制同一個引用進行填充。
另一種方式就是創(chuàng)建一個Generator接口,在泛型類中實現(xiàn)其next方法,然后通過泛型方法將泛型類toArray返回。
16.7 Arrays實用功能
Arrays.asList接收任意的序列或數(shù)組作為其參數(shù),并將其轉變?yōu)長ist容器。
System.arraycopy()用它復制數(shù)組比用for循環(huán)復制要快很多,不會自動包裝和自動拆包,兩個數(shù)組必須具有相同的確切類型。
Arrays.equals()數(shù)組相等的條件是元素個數(shù)必須相等,并且對應位置的元素也相等。數(shù)組相等是基于內容的,通過Object.equals()比較。
class CollectionData<T> extends ArrayList<T> {
public CollectionData(Generator<T> gen, int quantity) {
for (int i = 0; i < quantity; i++)
add(gen.next());
}
// A generic convenience method:
public static <T> CollectionData<T> list(Generator<T> gen, int quantity) {
return new CollectionData<T>(gen, quantity);
}
}
class Generated {
// Fill an existing array:
public static <T> T[] array(T[] a, Generator<T> gen) {
return new CollectionData<T>(gen, a.length).toArray(a);
}
// Create a new array:
@SuppressWarnings("unchecked")
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, size).toArray(a);
}
}
public class CompType implements Comparable<CompType> {
int i;
int j;
private static int count = 1;
public CompType(int n1, int n2) {
i = n1;
j = n2;
}
public String toString() {
String result = "[i = " + i + ", j = " + j + "]";
if (count++ % 3 == 0)
result += "\n";
return result;
}
public int compareTo(CompType rv) {
return (i < rv.i ? -1 : (i == rv.i ? 0 : 1));
}
private static Random r = new Random(47);
public static Generator<CompType> generator() {
return new Generator<CompType>() {
public CompType next() {
return new CompType(r.nextInt(100), r.nextInt(100));
}
};
}
public static void main(String[] args) {
CompType[] a = Generated.array(new CompType[12], generator());
System.out.println("before sorting:");
System.out.println(Arrays.toString(a));
Arrays.sort(a);
System.out.println("after sorting:");
System.out.println(Arrays.toString(a));
}
}
java重排序算法針對基本類型是快速排序,針對對象類型是穩(wěn)定歸并排序。無需擔心排序的性能,除非你可以證明排序部分的確是程序效率的瓶頸。
如果數(shù)組已經(jīng)排好序了,就可以使用Arrays.binarySearch()執(zhí)行快速查找。 如果找到目標返回值等于或大于0,如果數(shù)組包含重復的元素,則無法保證找到的是這些副本中的哪一個。
應該優(yōu)選容器而不是數(shù)組,只有在已證明性能成為問題時,才應該講程序重構為使用數(shù)組。