为什么转换为泛型类型会生效?

时间:2013-08-20 06:41:09

标签: java generics

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 个答案:

答案 0 :(得分:4)

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

由于类型擦除,类型参数T在编译时被替换为擦除。 无界类型参数的擦除是Object,而有界类型参数的擦除是表示上限的类型。因此,如果类中的类型参数具有上限 - Holder<T extends Number>,则T的删除将为Number。这意味着编译器将T替换为Number

因此,在这种情况下,由于T处于无界状态,因此其擦除为Object。因此,编译器将其替换为Object

即使转换删除了编译器错误,编译器仍会显示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警告。但那是无害的。

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


<强>参考:

答案 1 :(得分:1)

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

答案 2 :(得分:1)

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

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

答案 3 :(得分:0)

如果您认为在类型擦除之后所有类型参数最终都是简单的Object,那么您的问题就是整个Java泛型的使用。在我看来,这些是:

  1. 文档/开发人员间沟通/易读性/可维护性。
  2. 尽早避免逻辑错误(即静态错误)。
  3. 降低测试要求/允许重新调整测试工作的重点,使代码更加健壮。
  4. 不幸的是,很难让Generics在Java中保持完全向后兼容性和其他目标。结果是new T[size]无效。唯一的选择是new Object[size]。强制转换(T[])是告诉编译器和其他开发人员,这正是您的意图。特别是,编译器不会在此特定行中发出警告消息(这比全局禁用此类检查更安全)。