无论使用哪种类型的数组,数组标识符其实只是一个引用,指向在堆上创建的一个真实对象,这个数组对象用以保存指向其它对象的引用(基本类型保存的是值)。
1、数组的初始化:
下例总结了数组的初始化的几种方式:
public class ArrayOptions {
public static void main(String[] args) {
BerylliumSphere[] a; // 声明,未初始化
BerylliumSphere[] b = new BerylliumSphere[5];//自动初始化
print("b: " + Arrays.toString(b));//相当于System.out.println()
BerylliumSphere[] c = new BerylliumSphere[4];
for(int i = 0; i < c.length; i++)
if(c[i] == null) // Can test for null reference
c[i] = new BerylliumSphere();
BerylliumSphere[] d = { new BerylliumSphere(),
new BerylliumSphere(), new BerylliumSphere() //初始化
};
a = new BerylliumSphere[]{
new BerylliumSphere(), new BerylliumSphere(), //初始化
};
print("a.length = " + a.length); //输出
print("b.length = " + b.length);
print("c.length = " + c.length);
print("d.length = " + d.length);
a = d;
print("a.length = " + a.length);
int[] e;
int[] f = new int[5];
print("f: " + Arrays.toString(f));
int[] g = new int[4];
for(int i = 0; i < g.length; i++)
g[i] = i*i;
int[] h = { 11, 47, 93 };
//!print("e.length = " + e.length); //e没有初始化,不能使用
print("f.length = " + f.length);
print("g.length = " + g.length);
print("h.length = " + h.length);
e = h;
print("e.length = " + e.length);
e = new int[]{ 1, 2 };
print("e.length = " + e.length);
}
} /* Output:
b: [null, null, null, null, null]
a.length = 2
b.length = 5
c.length = 4
d.length = 3
a.length = 3
f: [0, 0, 0, 0, 0]
f.length = 5
g.length = 4
h.length = 3
e.length = 3
e.length = 2
*///:~
2、返回一个数组
返回一个数组与返回任何其他对象(实际上是返回使用)没什么区别。返回类型是数组类型即可,例如String[]。
3、多维数组
java中实际上没有多维数组,只有一维数组。多维数组被解释为数组的数组。创建多维数组很方便。对于基本类型的多维数组,可以使用花括号将每个向量分开:
public class MultidimensionalPrimitiveArray {
public static void main(String[] args) {
int[][] a = {
{ 1, 2, 3, },
{ 4, 5, 6, },
};
System.out.println(Arrays.deepToString(a));
}
} /* 输出
[[1, 2, 3], [4, 5, 6]]
数组中的构成矩阵的每个向量都可以具有任意的长度(这被称为粗糙数组):
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));
}
} /* Output:
[[], [[0], [0], [0, 0, 0, 0]], [[], [0, 0], [0, 0]], [[0, 0, 0], [0], [0, 0, 0, 0]], [[0, 0, 0], [0, 0, 0], [0], []], [[0], [], [0]]]
*///:~
第一个new创建了数组,其中的长度由随机数决定,其他维则没有定义。位于for循环内的第二个new则会决定第二维的长度;直到碰到第三个new,第三维的长度才得以确定。
3、数组与泛型
通常数组与泛型不能很好的结合。你不能实例化具有参数化类型的数组:
Peel<Banana> peels = new Peel<Banana>[10];//不合法的
擦除会移除参数类型的信息,而数组必须知道它们所持有的确切类型,以强制保证类型安全。但是你可以参数化数组本身的类型:
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);
}
}
一般而言,泛型在类或者方法的边界处很有效,但是在类或者方法的内部,擦除会使得泛型变得不适用。例如不能创建泛型数组:
public class ArrayOfGenericType<T> {
T[] array; // OK
@SuppressWarnings("unchecked")
public ArrayOfGenericType(int size) {
//! array = new T[size]; // Illegal
array = (T[])new Object[size]; // "unchecked" Warning 可以进行类型转化
}
// Illegal:
//! public <U> U[] makeArray() { return new U[10]; } 不能创建一个泛型数组
}
参考《Java编程思想》