请从Java Generics FAQ解释此声明

时间:2012-10-09 12:57:49

标签: java generics

有人可以解释以下声明的含义:

  

创建具有不可重新生成的组件类型的数组不是   允许的。

这是用Anjelika Langer's Java Generics FAQ

写的

3 个答案:

答案 0 :(得分:9)

  

不允许使用不可恢复的组件类型创建数组。

实际上意味着通用数组创建是非法的:

new T[...] // prohibited

不允许使用通用数组,因为数组在运行时包含有关其组件的信息。对于泛型而言,情况并非如此。泛型在编译器级别实现。因此,在创建数组时必须事先知道组件类型。

答案 1 :(得分:4)

  

Java编程语言不允许创建参数化类型的数组,即不允许新的T []

     

如果数组的元素类型不可恢复(第4.7节),则虚拟机无法执行前一段中描述的存储检查。这就是为什么禁止创建不可再生类型的数组的原因。可以声明其元素类型不可重新生成的数组类型的变量,但是任何为它们赋值的尝试都会产生未经检查的警告(第5.1.9节)。

您可以详细了解here 查看更多:

下面是代码示例,它显示了使用泛型类型的varargs时可能出现的问题。

public class ArrayBuilder {

public static <T> void addToList(List<T> listArg, T... elements) {
    for (T x : elements) {
        listArg.add(x);
    }
}

public static void faultyMethod(List<String>... l) {
    Object[] objectArray = l; // Valid
    objectArray[0] = Arrays.asList(42);
    String s = l[0].get(0); // ClassCastException thrown here
}

public static void main(String[] args) {

    List<String> stringListA = new ArrayList<String>();
    List<String> stringListB = new ArrayList<String>();

    ArrayBuilder.addToList(stringListA, "Seven", "Eight", "Nine");
    ArrayBuilder.addToList(stringListA, "Ten", "Eleven", "Twelve");
    List<List<String>> listOfStringLists = new ArrayList<List<String>>();
    ArrayBuilder.addToList(listOfStringLists, stringListA, stringListB);

    ArrayBuilder.faultyMethod(Arrays.asList("Hello!"),
            Arrays.asList("World!"));
}

}

当编译器遇到varargs方法时,它会将varargs形式参数转换为数组。但是,the Java programming language does not permit the creation of arrays of parameterized types。在方法ArrayBuilder.addToList中,编译器将varargs形式参数T...元素转换为形式参数T[]元素。但是,由于类型擦除,编译器会将varargs形式参数转换为Object[]元素。因此,存在堆污染的可能性。

以下语句将varargs形式参数l分配给Object数组objectArgs:

Object[] objectArray = l;

此声明可能会引入堆污染。与varargs形式参数l的参数化类型匹配的值可以分配给变量objectArray,因此可以分配给l。但是,编译器不会在此语句中生成未经检查的警告。编译器在将varargs形式参数List<String> ... l转换为形式参数List[]时已生成警告。本声明有效;变量l的类型为List[],它是Object[]的子类型。

因此,如果将任何类型的List对象分配给objectArray数组的任何数组组件,编译器不会发出警告或错误,如下所示:

objectArray[0] = Arrays.asList(42);

此语句使用包含一个Integer类型的对象的List对象分配给objectArray数组的第一个数组组件。

假设您使用以下语句调用ArrayBuilder.faultyMethod:

   ArrayBuilder.faultyMethod(Arrays.asList("Hello!"), Arrays.asList("World!"));

在运行时,JVM会在以下语句中抛出ClassCastException:

   // ClassCastException thrown here
   String s = l[0].get(0);

答案 2 :(得分:3)

如果您在该链接中进一步阅读,您会发现以下声明: -

Pair<String,String> is not a reifiable type, that is, it loses information as a 
result of type erasure and is at runtime represented as the raw type Pair 
instead of the exact type Pair<String,String>

来自JLS - Arrays的更多内容: -

  

<强>讨论

     

如果数组的元素类型不可恢复(第4.7节),则为虚拟   机器无法执行前面描述的存储检查   段。这就是为什么要创建不可再生类型的数组的原因   禁止。可以声明其元素的数组类型的变量   type是不可恢复的,但是任何为它们赋值的尝试都会   引起一个未经检查的警告(§5.1.9)。