【问题标题】:Please explain this statement from Java Generics FAQ请解释 Java 泛型常见问题解答中的此声明
【发布时间】:2012-10-09 12:57:48
【问题描述】:

谁能解释一下下面的语句是什么意思:

不能创建具有不可具体化组件类型的数组 允许。

这是写在Anjelika Langer's Java Generics FAQ

【问题讨论】:

标签: java generics


【解决方案1】:

不允许创建具有不可具体化组件类型的数组。

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

new T[...] // prohibited

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

【讨论】:

【解决方案2】:

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

如果数组的元素类型不可具体化(第 4.7 节),则虚拟机无法执行上一段中描述的存储检查。这就是为什么禁止创建不可具体化类型的数组的原因。可以声明其元素类型不可具体化的数组类型变量,但任何尝试为它们分配值都会引发未经检查的警告(第 5.1.9 节)。

您可以阅读更多关于它的信息here 查看更多:

下面的代码示例显示了如果将可变参数与泛型类型一起使用会出现什么问题。

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!"));
}

}

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

以下语句将可变参数形式参数l 分配给对象数组objectArgs:

Object[] objectArray = l;

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

【讨论】:

  • faultyMethod()的签名,或者方法的调用都没有问题。问题出在方法体内部,但与泛型数组创建无关。由于调用这个 vararg 方法需要创建一个泛型数组,这是语言规范中的一个漏洞。我们可以使用它作为后门来合法地创建一个泛型数组。 stackoverflow.com/questions/529085/…
  • @irreputable 是的。我不知道你为什么没有收到对该帖子的投票:)。
【解决方案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)。

【讨论】:

    猜你喜欢
    • 2017-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多