2

Java revisited中,代码摘录如下:

class Holder<T>{
  private T[] contents;
  private int index = 0;
  public Holder(int size){
    //contents = new T[size]; //compiler error - generic array creation
    contents = (T[]) new Object[size]; //workaround - casting Object[] to generic Type
  }...}

它用于创建通用数组,但根据类型擦除(我在 java 在线教程上检查过),在编译的类中T结束,所以强制转换会结束 ,这似乎与没有强制转换没有区别Object(T[])(Object[])

那么该铸造的功能或铸造的任何特殊含义是什么?任何提示都是感激的。

4

4 回答 4

4

演员需要告诉编译器从我们这边分配是好的。否则它将显示编译器错误。

由于类型擦除,类型参数T在编译时被它的擦除替换。无界类型参数的擦除是Object,而有界类型参数的擦除是表示上限的类型。所以,如果你在类中的类型参数有一个上限 - Holder<T extends Number>,那么擦除T将是Number。这意味着,将被编译器T替换为。Number

所以,在这种情况下,由于T在无界中,它的擦除是ObjectObject因此,它被编译器替换为。

即使转换消除了编译器错误,编译器仍会向您显示 Unchecked Cast 的警告。因为,强制转换不是类型安全的,如果您使用类型参数ClassCastException实例化泛型类型,则会在运行时失败。String

试试这个:

Holder<String> stringHolder = new Holder<>(5);
String[] contents = stringHolder.getContents();  // ClassCastException

创建泛型数组的一种更安全的方法是使用Array.newInstance方法。您需要将Class<T>参数传递给构造函数,然后使用以下代码:

public Holder(int size, Class<T> clazz){
    contents = (T[]) Array.newInstance(clazz, size);
}

在这里你也会看到Unchecked Cast警告。但这是无害的。

更安全的方法根本不是创建一个组件类型是类型参数的数组。您可以改为使用 an ArrayList<T>


参考:

于 2013-08-20T06:49:12.993 回答
1

T 只是一个占位符。当编译错误存在时,您无法实例化它。在编译时,您需要告诉编译器占位符呈现什么。在代码摘录的情况下,占位符是任何东西。

于 2013-08-20T06:46:58.803 回答
1

演员表的存在是为了摆脱 编译错误。它是创建通用数组的一种未经检查的方式。

即使ArrayList遵循相同的方法。您可以查看此答案以查看已检查和未检查的方法

于 2013-08-20T06:47:05.350 回答
0

如果您认为在类型擦除之后所有类型参数都以 simple Objects 结尾,那么您的问题是关于 Java 泛型作为一个整体的使用。在我看来,这些是:

  1. 文档/开发人员之间的沟通/易读性/可维护性。
  2. 尽可能早地避免逻辑错误(即静态地)。
  3. 减少测试要求/允许将测试工作重新集中在更超越的方面,并使代码更健壮。

不幸的是,当时很难在 Java 中使用泛型来保持完全的向后兼容性和其他目标。结果是new T[size]无效的。唯一的选择是new Object[size]。演员表(T[])是告诉编译器和其他开发人员这正是你想要的。特别是,编译器不会在此特定行中发出警告消息(这比全局禁用此类检查要安全得多)。

于 2013-08-20T07:22:21.487 回答