1.数组和其他容器相比是一种效率最高的存储和随机访问对象的方式,但是它的缺点是大小被固定。
2.数组可以持有基本类型,而泛型之前的容器则不能
3.无论使用什么类型的数组,数组标识符其实只是一个引用,指向在堆中创建的一个真实对象,这个对象用于保存指向其他对象的引用。对象数组和基本类
型数组在使用上几乎是相同的,唯一的区别就是对象数组保存的是引用,基本类型数组保存基本类型的值。下面是数组的各种初始化方法:
public class ArrayOptions {
public static void main(String[] args) {
// Arrays of objects:
BerylliumSphere[] a; // Local uninitialized variable局部初始化
BerylliumSphere[] b = new BerylliumSphere[5];
// The references inside the array are
// automatically initialized to null:
print("b: " + Arrays.toString(b));
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();
// Aggregate initialization:采用的是聚集初始化语法来初始化数组
BerylliumSphere[] d = { new BerylliumSphere(),
new BerylliumSphere(), new BerylliumSphere()
};
// Dynamic aggregate initialization:这是动态聚集初始化。上面的必须在必须在定义出使用。动态聚集初始化就没有这个限制
a = new BerylliumSphere[]{
new BerylliumSphere(), new BerylliumSphere(),
};
// (Trailing comma is optional in both cases)
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);
// Arrays of primitives:
int[] e; // Null reference
int[] f = new int[5];
// The primitives inside the array are
// automatically initialized to zero:
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 };
// Compile error: variable e not initialized:
//!print("e.length = " + e.length);
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:
新生成一个对象数组时,其中所有的引用都被自动化为null,所以检查其中的引用是否为null,即可知道数组的某个位置是否存有对象。同样,基本类型的
数组如果是数值类型,被自动初始化为0,如果是字符型,被自动化为(char)O;如果是boolean,自动初始化为false。
4.数组有个字段length,表示数组能够存储多少元素。
5.private static Random rand = new Random(47);
static final String[] FLAVORS = { "Chocolate", "Strawberry",
"Vanilla Fudge Swirl", "Mint Chip", "Mocha Almond Fudge",
"Rum Raisin", "Praline Cream", "Mud Pie" };
public static String[] flavorSet(int n) {
if (n > FLAVORS.length)
throw new IllegalArgumentException("Set too big");
String[] results = new String[n];
boolean[] picked = new boolean[FLAVORS.length];
for (int i = 0; i < n; i++) {
int t;
do
t = rand.nextInt(FLAVORS.length);
while (picked[t]);
results[i] = FLAVORS[t];
picked[t] = true;
}
return results;
}
注意上面的实现,随机选择,确保返回的数组中没有重复的元素。
6.多维数组创建很方便,例如:
public class MultidimensionalPrimitiveArray {
public static void main(String[] args) {
int[][] a = {
{ 1, 2, 3, },
{ 4, 5, 6, },
};
System.out.println(Arrays.deepToString(a));//该方法可以将多维数组转换成多个String
}
}
数组中构成矩阵的每个向量都可以具有任意的长度(这被称为粗糙数组):
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));
}
}
也可以用花括号来初始化:
public class MultidimensionalObjectArrays {
public static void main(String[] args) {
BerylliumSphere[][] spheres = {
{ new BerylliumSphere(), new BerylliumSphere() },
{ new BerylliumSphere(), new BerylliumSphere(),
new BerylliumSphere(), new BerylliumSphere() },
{ new BerylliumSphere(), new BerylliumSphere(),
new BerylliumSphere(), new BerylliumSphere(),
new BerylliumSphere(), new BerylliumSphere(),
new BerylliumSphere(), new BerylliumSphere() },
};
System.out.println(Arrays.deepToString(spheres));
}
}
7.使用参数化方法而不是使用参数化类的好处是,不必为需要应用的每种不同的类型都使用一个参数去实例化这个类。当然,不能总是选择参数化方法而不
是参数化类,但是它是首选:
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);
}
}
8.不能创建泛型数组这一说法并不十分准确。例如:
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>();
}
} ///:~
可以看到,数组元素可以参数化。
9.注意这种用法:
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]; }
}
10
import java.util.Arrays;
public class FillingArrays {
public static void main(String[] args) {
int size = 6;
boolean[] a1 = new boolean[size];
byte[] a2 = new byte[size];
char[] a3 = new char[size];
short[] a4 = new short[size];
int[] a5 = new int[size];
long[] a6 = new long[size];
float[] a7 = new float[size];
double[] a8 = new double[size];
String[] a9 = new String[size];
Arrays.fill(a1, true);
System.out.println("a1 = " + Arrays.toString(a1));
Arrays.fill(a2, (byte) 11);
System.out.println("a2 = " + Arrays.toString(a2));
Arrays.fill(a3, 'x');
System.out.println("a3 = " + Arrays.toString(a3));
Arrays.fill(a4, (short) 17);
System.out.println("a4 = " + Arrays.toString(a4));
Arrays.fill(a5, 19);
System.out.println("a5 = " + Arrays.toString(a5));
Arrays.fill(a6, 23);
System.out.println("a6 = " + Arrays.toString(a6));
Arrays.fill(a7, 29);
System.out.println("a7 = " + Arrays.toString(a7));
Arrays.fill(a8, 47);
System.out.println("a8 = " + Arrays.toString(a8));
Arrays.fill(a9, "Hello");
System.out.println("a9 = " + Arrays.toString(a9));
// Manipulating ranges:
Arrays.fill(a9, 3, 5, "World");
System.out.println("a9 = " + Arrays.toString(a9));
}
}
Arrays类的fill方法
fill
public static void fill(boolean[] a,
boolean val)
Assigns the specified boolean value to each element of the specified array of booleans.
Parameters:
a - the array to be filled.
val - the value to be stored in all elements of the array.
fill方法只能用同一个值填充数组的各个位置,针对对象数组,就是复制同一个引用进行填充。
11.
import java.util.Arrays;
public class CopyingArrays {
public static void main(String[] args) {
int[] i = new int[7];
int[] j = new int[10];
Arrays.fill(i, 47);
Arrays.fill(j, 99);
System.out.println("i = " + Arrays.toString(i));
System.out.println("j = " + Arrays.toString(j));
System.arraycopy(i, 0, j, 0, i.length);
System.out.println("j = " + Arrays.toString(j));
int[] k = new int[5];
Arrays.fill(k, 103);
System.arraycopy(i, 0, k, 0, k.length);
System.out.println("k = " + Arrays.toString(k));
Arrays.fill(k, 103);
System.arraycopy(k, 0, i, 0, k.length);
System.out.println("i = " + Arrays.toString(i));
// Objects:
Integer[] u = new Integer[10];
Integer[] v = new Integer[5];
Arrays.fill(u, new Integer(47));
Arrays.fill(v, new Integer(99));
System.out.println("u = " + Arrays.toString(u));
System.out.println("v = " + Arrays.toString(v));
System.arraycopy(v, 0, u, u.length/2, v.length);
System.out.println("u = " + Arrays.toString(u));
}
}
System类的静态方法
它比用for循环复制数组要快很多。
arraycopy
public static void arraycopy(Object src,
int srcPos,
Object dest,
int destPos,
int length)
Copies an array from the specified source array, beginning at the specified position, to the specified position of the destination
array. A subsequence of array components are copied from the source array referenced by src to the destination array referenced by dest.
The number of components copied is equal to the length argument. The components at positions srcPos through srcPos+length-1 in the
source array are copied into positions destPos through destPos+length-1, respectively, of the destination array.
Parameters:
src - the source array.
srcPos - starting position in the source array.
dest - the destination array.
destPos - starting position in the destination data.
length - the number of array elements to be copied.
上面的例子说明,基本类型与对象类型数组都可以复制。但是,如果复制对象数组,只是复制了对象的引用而不是对象本身的拷贝,这被称为浅复制。这个方法不会自动包装和拆包,两个数组必须具有相同的确切类型。
12.
Arrays类的静态方法:
equals
public static boolean equals(Object[] a,
Object[] a2)
Returns true if the two specified arrays of Objects are equal to one another. The two arrays are considered equal if both arrays
contain the same number of elements, and all corresponding pairs of elements in the two arrays are equal. Two objects e1 and e2 are
considered equal if (e1==null ? e2==null : e1.equals(e2)). In other words, the two arrays are equal if they contain the same elements in
the same order. Also, two array references are considered equal if both are null.
Parameters:
a - one array to be tested for equality.
a2 - the other array to be tested for equality.
Returns:
true if the two arrays are equal.
public class ComparingArrays {
public static void main(String[] args) {
int[] a1 = new int[10];
int[] a2 = new int[10];
Arrays.fill(a1, 47);
Arrays.fill(a2, 47);
System.out.println(Arrays.equals(a1, a2));
a2[3] = 11;
System.out.println(Arrays.equals(a1, a2));
String[] s1 = new String[4];
Arrays.fill(s1, "Hi");
String[] s2 = { new String("Hi"), new String("Hi"),
new String("Hi"), new String("Hi") };
System.out.println(Arrays.equals(s1, s2));
}
}
数组s1的所有元素都指向同一个元素,而s2包含不同的元素,但是比较的结果为true,数组的比较是基于内容的比较。
13.基本类型、包装类型、String都是值传递,即不管在函数里面怎么修改,原来的值不变;
自定义类型都是引用传递,即在函数里面的修改,会影响到原来的值;
数组,不管是基本类型、包装类型还是自定义类型,作参数数都是引用传递,会影响到原来的值;
2.数组可以持有基本类型,而泛型之前的容器则不能
3.无论使用什么类型的数组,数组标识符其实只是一个引用,指向在堆中创建的一个真实对象,这个对象用于保存指向其他对象的引用。对象数组和基本类
型数组在使用上几乎是相同的,唯一的区别就是对象数组保存的是引用,基本类型数组保存基本类型的值。下面是数组的各种初始化方法:
public class ArrayOptions {
public static void main(String[] args) {
// Arrays of objects:
BerylliumSphere[] a; // Local uninitialized variable局部初始化
BerylliumSphere[] b = new BerylliumSphere[5];
// The references inside the array are
// automatically initialized to null:
print("b: " + Arrays.toString(b));
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();
// Aggregate initialization:采用的是聚集初始化语法来初始化数组
BerylliumSphere[] d = { new BerylliumSphere(),
new BerylliumSphere(), new BerylliumSphere()
};
// Dynamic aggregate initialization:这是动态聚集初始化。上面的必须在必须在定义出使用。动态聚集初始化就没有这个限制
a = new BerylliumSphere[]{
new BerylliumSphere(), new BerylliumSphere(),
};
// (Trailing comma is optional in both cases)
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);
// Arrays of primitives:
int[] e; // Null reference
int[] f = new int[5];
// The primitives inside the array are
// automatically initialized to zero:
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 };
// Compile error: variable e not initialized:
//!print("e.length = " + e.length);
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:
新生成一个对象数组时,其中所有的引用都被自动化为null,所以检查其中的引用是否为null,即可知道数组的某个位置是否存有对象。同样,基本类型的
数组如果是数值类型,被自动初始化为0,如果是字符型,被自动化为(char)O;如果是boolean,自动初始化为false。
4.数组有个字段length,表示数组能够存储多少元素。
5.private static Random rand = new Random(47);
static final String[] FLAVORS = { "Chocolate", "Strawberry",
"Vanilla Fudge Swirl", "Mint Chip", "Mocha Almond Fudge",
"Rum Raisin", "Praline Cream", "Mud Pie" };
public static String[] flavorSet(int n) {
if (n > FLAVORS.length)
throw new IllegalArgumentException("Set too big");
String[] results = new String[n];
boolean[] picked = new boolean[FLAVORS.length];
for (int i = 0; i < n; i++) {
int t;
do
t = rand.nextInt(FLAVORS.length);
while (picked[t]);
results[i] = FLAVORS[t];
picked[t] = true;
}
return results;
}
注意上面的实现,随机选择,确保返回的数组中没有重复的元素。
6.多维数组创建很方便,例如:
public class MultidimensionalPrimitiveArray {
public static void main(String[] args) {
int[][] a = {
{ 1, 2, 3, },
{ 4, 5, 6, },
};
System.out.println(Arrays.deepToString(a));//该方法可以将多维数组转换成多个String
}
}
数组中构成矩阵的每个向量都可以具有任意的长度(这被称为粗糙数组):
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));
}
}
也可以用花括号来初始化:
public class MultidimensionalObjectArrays {
public static void main(String[] args) {
BerylliumSphere[][] spheres = {
{ new BerylliumSphere(), new BerylliumSphere() },
{ new BerylliumSphere(), new BerylliumSphere(),
new BerylliumSphere(), new BerylliumSphere() },
{ new BerylliumSphere(), new BerylliumSphere(),
new BerylliumSphere(), new BerylliumSphere(),
new BerylliumSphere(), new BerylliumSphere(),
new BerylliumSphere(), new BerylliumSphere() },
};
System.out.println(Arrays.deepToString(spheres));
}
}
7.使用参数化方法而不是使用参数化类的好处是,不必为需要应用的每种不同的类型都使用一个参数去实例化这个类。当然,不能总是选择参数化方法而不
是参数化类,但是它是首选:
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);
}
}
8.不能创建泛型数组这一说法并不十分准确。例如:
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>();
}
} ///:~
可以看到,数组元素可以参数化。
9.注意这种用法:
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]; }
}
10
import java.util.Arrays;
public class FillingArrays {
public static void main(String[] args) {
int size = 6;
boolean[] a1 = new boolean[size];
byte[] a2 = new byte[size];
char[] a3 = new char[size];
short[] a4 = new short[size];
int[] a5 = new int[size];
long[] a6 = new long[size];
float[] a7 = new float[size];
double[] a8 = new double[size];
String[] a9 = new String[size];
Arrays.fill(a1, true);
System.out.println("a1 = " + Arrays.toString(a1));
Arrays.fill(a2, (byte) 11);
System.out.println("a2 = " + Arrays.toString(a2));
Arrays.fill(a3, 'x');
System.out.println("a3 = " + Arrays.toString(a3));
Arrays.fill(a4, (short) 17);
System.out.println("a4 = " + Arrays.toString(a4));
Arrays.fill(a5, 19);
System.out.println("a5 = " + Arrays.toString(a5));
Arrays.fill(a6, 23);
System.out.println("a6 = " + Arrays.toString(a6));
Arrays.fill(a7, 29);
System.out.println("a7 = " + Arrays.toString(a7));
Arrays.fill(a8, 47);
System.out.println("a8 = " + Arrays.toString(a8));
Arrays.fill(a9, "Hello");
System.out.println("a9 = " + Arrays.toString(a9));
// Manipulating ranges:
Arrays.fill(a9, 3, 5, "World");
System.out.println("a9 = " + Arrays.toString(a9));
}
}
Arrays类的fill方法
fill
public static void fill(boolean[] a,
boolean val)
Assigns the specified boolean value to each element of the specified array of booleans.
Parameters:
a - the array to be filled.
val - the value to be stored in all elements of the array.
fill方法只能用同一个值填充数组的各个位置,针对对象数组,就是复制同一个引用进行填充。
11.
import java.util.Arrays;
public class CopyingArrays {
public static void main(String[] args) {
int[] i = new int[7];
int[] j = new int[10];
Arrays.fill(i, 47);
Arrays.fill(j, 99);
System.out.println("i = " + Arrays.toString(i));
System.out.println("j = " + Arrays.toString(j));
System.arraycopy(i, 0, j, 0, i.length);
System.out.println("j = " + Arrays.toString(j));
int[] k = new int[5];
Arrays.fill(k, 103);
System.arraycopy(i, 0, k, 0, k.length);
System.out.println("k = " + Arrays.toString(k));
Arrays.fill(k, 103);
System.arraycopy(k, 0, i, 0, k.length);
System.out.println("i = " + Arrays.toString(i));
// Objects:
Integer[] u = new Integer[10];
Integer[] v = new Integer[5];
Arrays.fill(u, new Integer(47));
Arrays.fill(v, new Integer(99));
System.out.println("u = " + Arrays.toString(u));
System.out.println("v = " + Arrays.toString(v));
System.arraycopy(v, 0, u, u.length/2, v.length);
System.out.println("u = " + Arrays.toString(u));
}
}
System类的静态方法
它比用for循环复制数组要快很多。
arraycopy
public static void arraycopy(Object src,
int srcPos,
Object dest,
int destPos,
int length)
Copies an array from the specified source array, beginning at the specified position, to the specified position of the destination
array. A subsequence of array components are copied from the source array referenced by src to the destination array referenced by dest.
The number of components copied is equal to the length argument. The components at positions srcPos through srcPos+length-1 in the
source array are copied into positions destPos through destPos+length-1, respectively, of the destination array.
Parameters:
src - the source array.
srcPos - starting position in the source array.
dest - the destination array.
destPos - starting position in the destination data.
length - the number of array elements to be copied.
上面的例子说明,基本类型与对象类型数组都可以复制。但是,如果复制对象数组,只是复制了对象的引用而不是对象本身的拷贝,这被称为浅复制。这个方法不会自动包装和拆包,两个数组必须具有相同的确切类型。
12.
Arrays类的静态方法:
equals
public static boolean equals(Object[] a,
Object[] a2)
Returns true if the two specified arrays of Objects are equal to one another. The two arrays are considered equal if both arrays
contain the same number of elements, and all corresponding pairs of elements in the two arrays are equal. Two objects e1 and e2 are
considered equal if (e1==null ? e2==null : e1.equals(e2)). In other words, the two arrays are equal if they contain the same elements in
the same order. Also, two array references are considered equal if both are null.
Parameters:
a - one array to be tested for equality.
a2 - the other array to be tested for equality.
Returns:
true if the two arrays are equal.
public class ComparingArrays {
public static void main(String[] args) {
int[] a1 = new int[10];
int[] a2 = new int[10];
Arrays.fill(a1, 47);
Arrays.fill(a2, 47);
System.out.println(Arrays.equals(a1, a2));
a2[3] = 11;
System.out.println(Arrays.equals(a1, a2));
String[] s1 = new String[4];
Arrays.fill(s1, "Hi");
String[] s2 = { new String("Hi"), new String("Hi"),
new String("Hi"), new String("Hi") };
System.out.println(Arrays.equals(s1, s2));
}
}
数组s1的所有元素都指向同一个元素,而s2包含不同的元素,但是比较的结果为true,数组的比较是基于内容的比较。
13.基本类型、包装类型、String都是值传递,即不管在函数里面怎么修改,原来的值不变;
自定义类型都是引用传递,即在函数里面的修改,会影响到原来的值;
数组,不管是基本类型、包装类型还是自定义类型,作参数数都是引用传递,会影响到原来的值;