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

Java 为什么强制转换为泛型类型会生效?,java,generics,Java,Generics,在上,代码摘录如下: 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

在上,代码摘录如下:

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
  }...}
类持有者{
私有T[]内容;
私有整数指数=0;
公共持有人(整数){
//contents=new T[size];//编译器错误-泛型数组创建
contents=(T[])新对象[size];//解决方法-将对象[]转换为泛型类型
}...}
它用于创建泛型数组,但根据类型擦除(我在java在线教程中检查过),
T
在编译的类中结束为
Object
,因此cast
(T[])
将结束为
(Object[])
,这似乎与不施法没有什么区别


那么,这种铸造的功能是什么,或者对铸造有什么特殊意义呢?任何暗示都是感激的

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

出现强制转换是为了消除编译错误。这是一种创建通用数组的方法


即使是
ArrayList
也遵循相同的方法。您可以查看checked和unchecked方法

强制转换需要告诉编译器我们的赋值是正确的。否则它将显示编译器错误

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

因此,在这种情况下,由于无界中的
T
,其擦除是
Object
。因此,编译器将其替换为
对象

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

试试这个:

Holder<String> stringHolder = new Holder<>(5);
String[] contents = stringHolder.getContents();  // ClassCastException
在这里,您还将看到
未选中的强制转换
警告。但这是无害的

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


参考资料:


如果您认为在类型擦除之后,所有类型参数都会以简单的<代码>对象< /代码> s出现,您的问题是关于java泛型的使用。我认为这些是:

  • 文件/开发者间沟通/易读性/可维护性
  • 尽早避免逻辑错误(即静态)
  • 减少测试需求/允许将测试工作重新集中在更卓越的方面,并使代码更健壮

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

    如果您尝试不使用强制转换,您将立即看到为什么在运行时强制转换不起任何作用。这与类型转换不同。它所做的是告诉编译器将某个特定表达式视为不同的类型。哦,它似乎只是编译器的占位符,很抱歉这个愚蠢的问题。“在这里,您还将看到未选中强制转换警告。但这是无害的。”不,它不是。尝试在as
    clazz
    中传递
    int.class
    “您需要将类参数传递给构造函数”。问题是
    Holder
    类不需要知道类型参数来执行其功能。因此,强迫用户传入类对象并不理想。谢谢,我刚才发现它是一个糟糕的设计,因为无法获取内容,这太糟糕了。
    public Holder(int size, Class<T> clazz){
        contents = (T[]) Array.newInstance(clazz, size);
    }