企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
## 泛型数组 一般来说,数组和泛型并不能很好的结合。你不能实例化参数化类型的数组: ```Java Peel<Banana>[] peels = new Peel<Banana>[10]; // Illegal ``` 类型擦除需要删除参数类型信息,而且数组必须知道它们所保存的确切类型,以强制保证类型安全。 但是,可以参数化数组本身的类型: ```Java // arrays/ParameterizedArrayType.java 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); } } ``` 比起使用参数化类,使用参数化方法很方便。您不必为应用它的每个不同类型都实例化一个带有参数的类,但是可以使它成为 **静态** 的。你不能总是选择使用参数化方法而不用参数化的类,但通常参数化方法是更好的选择。 你不能创建泛型类型的数组,这种说法并不完全正确。是的,编译器不会让你 *实例化* 一个泛型的数组。但是,它将允许您创建对此类数组的引用。例如: ```Java List<String>[] ls; ``` 无可争议的,这可以通过编译。尽管不能创建包含泛型的实际数组对象,但是你可以创建一个非泛型的数组并对其进行强制类型转换: ```Java // arrays/ArrayOfGenerics.java import java.util.*; public class ArrayOfGenerics { @SuppressWarnings("unchecked") public static void main(String[] args) { List<String>[] ls; List[] la = new List[10]; ls = (List<String>[])la; // Unchecked cast ls[0] = new ArrayList<>(); //- ls[1] = new ArrayList<Integer>(); // error: incompatible types: ArrayList<Integer> // cannot be converted to List<String> // 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<>(); // However, if your needs are straightforward it is // possible to create an array of generics, albeit // with an "unchecked cast" warning: List<BerylliumSphere>[] spheres = (List<BerylliumSphere>[])new List[10]; Arrays.setAll(spheres, n -> new ArrayList<>()); } } ``` 一旦你有了对 **List<String>[]** 的引用 , 你会发现多了一些编译时检查。问题是数组是协变的,所以 **List<String>[]** 也是一个 **Object[]** ,你可以用这来将 **ArrayList<Integer> ** 分配进你的数组,在编译或者运行时都不会出错。 如果你知道你不会进行向上类型转换,你的需求相对简单,那么可以创建一个泛型数组,它将提供基本的编译时类型检查。然而,一个泛型 **Collection** 实际上是一个比泛型数组更好的选择。 一般来说,您会发现泛型在类或方法的边界上是有效的。在内部,擦除常常会使泛型不可使用。所以,就像下面的例子,不能创建泛型类型的数组: ```Java // arrays/ArrayOfGenericType.java public class ArrayOfGenericType<T> { T[] array; // OK @SuppressWarnings("unchecked") public ArrayOfGenericType(int size) { // error: generic array creation: //- array = new T[size]; array = (T[])new Object[size]; // unchecked cast } // error: generic array creation: //- public <U> U[] makeArray() { return new U[10]; } } ``` 擦除再次从中作梗,这个例子试图创建已经擦除的类型数组,因此它们是未知的类型。你可以创建一个 **对象** 数组,然后对其进行强制类型转换,但如果没有 **@SuppressWarnings** 注释,你将会得到一个 "unchecked" 警告,因为数组实际上不真正支持而且将对类型 **T** 动态检查 。这就是说,如果我创建了一个 **String[]** , Java将在编译时和运行时强制执行,我只能在数组中放置字符串对象。然而,如果我创建一个 **Object[]** ,我可以把除了基元类型外的任何东西放入数组。