创建和初始化数组
基本示例
int[] numbers1 = new int[3]; //数组为3个int值,默认值为0 int[] numbers2 = { 1, 2, 3 }; //3 个 int 值的字面量数组 int[] numbers3 = new int[] { 1, 2, 3 }; //初始化 3 个 int 值的数组 int[][] numbers4 = { { 1, 2 }, { 3, 4, 5 } }; //锯齿状字面量数组 int[][] numbers5 = new int[5][]; //锯齿状数组,一维长度是5 int[][] numbers6 = new int[5][4]; //多维数组 5*4
可以使用任何原始类型或者引用类型创建数组。
float[] boats = new float[5]; //5个 32 位浮点数的数组。 double[] header = new double[] { 4.56, 332.267, 7.0, 0.3367, 10.0 }; //5个 64 位浮点数的数组。 String[] theory = new String[] { "a", "b", "c" }; //3个字符串的数组(引用类型)。 Object[] dArt = new Object[] { new Object(), "We love Stack Overflow.", new Integer(3) }; //3个对象的数组(引用类型)。
对于最后一个示例,请注意数组中允许声明的数组类型的子类型。
用户定义类型的数组也可以像原始类型一样构建
UserDefinedClass[] udType = new UserDefinedClass[5];
数组、集合和流
//版本 ≥ Java SE 1.2
//参数需要对象,而不是原语 //此处为 int 127 进行自动封箱操作 Integer[] initial = { 127, Integer.valueOf( 42 ) }; List toList = Arrays.asList( initial ); //Fixed size! //注意:适用于所有集合 Integer[] fromCollection = toList.toArray( new Integer[toList.size()] ); //Java 不允许您创建参数化类型的数组 List[] list = new ArrayList[2]; //编译错误 //Streams - JDK 8+ Stream toStream = Arrays.stream( initial ); Integer[] fromStream = toStream.toArray( Integer[]::new );
创建和初始化多维数组
创建多维数组最简单的方法如下:
int[][] a = new int[2][3];
它将创建两个三长 int 数组——a[0] 和 a[1]。
这与矩形多维数组的经典 C 风格初始化非常相似。
我们可以同时创建和初始化:
int[][] a = { {1, 2}, {3, 4}, {5, 6} };
与仅支持矩形多维数组的 C 不同,内部数组不需要具有相同的长度,甚至不需要定义:
int[][] a = { {1}, {2, 3}, null };
其中a[0] 是一个长度为一的 int 数组,而 a[1] 是一个两个长度的 int 数组,而 a[2] 为空。
像这样的数组被称为锯齿状数组或者参差不齐的数组,也就是说,它们是数组的数组。
Java中的多维数组是通过数组的数组来实现的,例如:array[i][j][k]等价于((array[i])[j])[k]。
与 C# 不同,Java 不支持语法 array[i,j]。
创建和初始化泛型类型数组
在泛型类中,由于类型擦除,泛型类型的数组不能像这样初始化:
public class MyGenericClass { private T[] a; public MyGenericClass() { a = new T[5]; //Compile time error: generic array creation } }
相反,它们可以使用以下方法之一创建:(请注意,这些将生成未经检查的
警告)
- 通过创建一个 Object 数组,并将其转换为泛型类型:
a = (T[]) new Object[5];
这是最简单的方法,但由于底层数组仍然是 Object[] 类型,因此该方法不提供类型安全。因此,这种创建数组的方法最好只在泛型类中使用 -- 没有公开。
- 通过将 Array.newInstance 与类参数一起使用:
public MyGenericClass(Class clazz) { a = (T[]) Array.newInstance(clazz, 5); }
这里必须将 T 的类显式传递给构造函数。 Array.newInstance 的返回类型始终是 Object。但是,这种方法更安全,因为新创建的数组始终是 T[] 类型,因此可以安全地外部化。
初始化后填充数组
版本 ≥ Java SE 1.2
Arrays.fill() can be used to fill an array with the same value after initialization: Arrays.fill(array8, "abc"); //{ "abc", "abc", "abc" }
fill() 还可以为数组指定范围的每个元素赋值:
Arrays.fill(array8, 1, 2, "aaa"); //Placing "aaa" from index 1 to 2.
版本 ≥ Java SE 8
从 Java 版本 8 开始,setAll 方法及其 Concurrent 等效并行 SetAll 可用于将数组的每个元素设置为生成的值。
这些方法被传递一个生成器函数,该函数接受一个索引并返回该位置的必需值。
以下示例创建一个整数数组并将其所有元素设置为其各自的索引值:
int[] array = new int[5]; Arrays.setAll(array, i -> i); //The array becomes { 0, 1, 2, 3, 4 }.
Java 提供了多种定义和初始化数组的方法,包括文字和构造函数符号。
使用 new Type[length] 构造函数声明数组时,每个元素都将使用以下默认值进行初始化:
- 0 表示原始数值类型:byte、short、int、long、float 和 double。
- '\u0000 '(空字符)用于 char 类型。
- 布尔类型为 false。
- 引用类型为 null。
//创建和初始化基本类型数组 int[] array1 = new int[] { 1, 2, 3 }; //Create an array with new operator and array initializer. int[] array2 = { 1, 2, 3 }; //Shortcut syntax with array initializer. int[] array3 = new int[3]; //Equivalent to { 0, 0, 0 } int[] array4 = null; //The array itself is an object, so it //can be set as null.
声明数组时,[] 将作为类型的一部分出现在声明的开头(在类型名称之后),或者作为特定变量的声明符的一部分(在变量名称之后),或者两者兼而有之:
int array5[]; /* equivalent to/int[] array5; int a, b[], c[][];/equivalent to/int a; int[] b; int[][] c; int[] a, b[];/equivalent to/int[] a; int[][] b; int a, []b, c[][];/Compilation Error, because [] is not part of the type at beginning of the declaration, rather it is before 'b'.///The same rules apply when declaring a method that returns an array: int foo()[] { … }/equivalent to */int[] foo() { … }
在下面的示例中,两个声明都是正确的,并且可以编译和运行而不会出现任何问题。
但是,Java 编码约定和 Google Java 样式教程都不鼓励在变量名后使用方括号的形式——方括号标识数组类型并应与类型名称一起出现。
方法返回签名也应该使用相同的方法。
float array[]; /* and/int foo()[] { … }/are discouraged/float[] array;/and/int[] foo() { … }/are encouraged */
不鼓励的类型是为了适应转换 C 用户,他们熟悉 C 的语法,在变量名后面有括号。