Java泛型:为什么我的@SuppressWarnings(";unchecked";)在这种情况下有效,而在另一种情况下无效?

Java泛型:为什么我的@SuppressWarnings(";unchecked";)在这种情况下有效,而在另一种情况下无效?,java,generics,type-erasure,Java,Generics,Type Erasure,这个问题和这个类似,但我无法从中找到解决方案 作为练习,我从头开始构建一个哈希表结构。所以我写了一个类LinkedListDemo辅助到HashTableDemo;LinkedListDemo类测试非常好。特别是,中的以下子例程在运行时不会导致ClassCastException错误: public LinkedListDemo<S, T> reverse() { if (count == 0) return null;

这个问题和这个类似,但我无法从中找到解决方案

作为练习,我从头开始构建一个哈希表结构。所以我写了一个类LinkedListDemo辅助到HashTableDemo;LinkedListDemo类测试非常好。特别是,中的以下子例程在运行时不会导致ClassCastException错误:

    public LinkedListDemo<S, T> reverse() {

        if (count == 0)
            return null;

        @SuppressWarnings("unchecked")
        S[] keys = (S[]) new Object[count];
        @SuppressWarnings("unchecked")
        T[] vals = (T[]) new Object[count];

        ListNode<S, T> runner = head;
        for (int k = 0; k < count; k++) {

            keys[k] = runner.pair.getKey();
            vals[k] = runner.pair.getValue();

            runner = runner.next;

        }

        ArrayUtils.reverse(keys);
        ArrayUtils.reverse(vals);

        return new LinkedListDemo<S, T>(keys, vals);

    }
公共LinkedListDemo反向(){ 如果(计数=0) 返回null; @抑制警告(“未选中”) S[]键=(S[])新对象[计数]; @抑制警告(“未选中”) T[]VAL=(T[])新对象[计数]; ListNode runner=头部; for(int k=0;k 而在我的HashTable类中,以下内容是:

public class HashTableDemo<S, T> {

    private LinkedListDemo<S, T>[] table = (LinkedListDemo<S, T>[]) new Object[10]; 

// more code...

}
公共类HashTableDemo{
私有LinkedListDemo[]表=(LinkedListDemo[])新对象[10];
//更多代码。。。
}
有人知道Java的HashMap类是如何绕过这个问题的,和/或我是如何做到的吗?我试着按照上面链接中的建议在构造函数中创建一个中间变量,但没有成功

这将编译:

@SuppressWarnings("unchecked") // this is okay because [insert reasoning here]
private LinkedListDemo<S, T>[] table =
        (LinkedListDemo<S, T>[]) new LinkedListDemo<?, ?>[10];
@SuppressWarnings(“unchecked”)//这没关系,因为[在这里插入推理]
私有LinkedListDemo[]表=
(LinkedListDemo[])新LinkedListDemo[10];
代码错误的原因是
对象[]
不是
LinkedListDemo[]
,类似于
对象
不是
LinkedListDemo

早期未选中的强制转换有效,因为在运行时,
S[]
T[]
已访问
Object[]

通常,不鼓励使用参数化类型的数组,因为它们的存在本身是不安全的。这是因为:

  • 数组是协变的-一个
    LinkedListDemo[]
    是一个
    对象[]
    。因此,可以将
    分配给
    对象[]
    变量,然后将
    字符串
    分配为元素-这在编译时是合法的,但至少在运行时会失败,出现
    ArrayStoreException
    ,因为数组执行运行时类型检查
  • 泛型类型信息在运行时不可用,因为它已被编译器删除。可以再次将
    分配给
    对象[]
    变量,但这次将
    链接列表
    分配为元素。在运行时,数组只会看到添加了一个普通的
    LinkedListDemo
    ,因此如果泛型类型错误,它不会立即失败。这可能会在以后某个时候导致意外的
    ClassCastException
    s
请参阅我的答案,以获得关于此问题的更全面的解释和示例。另请参见Angelika Langer的泛型常见问题解答中的这一精彩解释:

这样做的好处是,简单地使用
列表
将更容易、更安全。如果您最终决定坚持使用
LinkedListDemo[]
,请确保它作为一个实现细节被小心地隐藏起来,并了解它如何被误用

其他几个杂项注释:

  • @SuppressWarnings(“unchecked”)
    除了抑制未经检查的强制转换编译器警告之外,什么都不做。它本质上是在说“相信我,我知道我在做什么”-但你仍然需要小心,未经检查的演员阵容没有被滥用。有关更多信息,请参阅本文:
  • 与所有的核心API类一样,它也是可用的,因此如果您想更好地了解它的内部工作原理,您可以随意查看它

您应该在运行时获得ClassCastException。也许你没有彻底测试。赋值
S[]键=(S[])新对象[count]S
对象时,code>才是合法的。如果
S
是,比如说
String
@NathanielWaisbrot不是真的,它将失败,因为
S
被擦除到
对象
-这就是未选中强制转换的含义。谢谢Paul;但从广义上讲,为什么LinkedListDemo在运行时不被类似地擦除?@VictorAlvarez
LinkedListDemo
是一种可重新定义的类型,这意味着它在运行时仍然可用
LinkedListDemo[]
将被擦除到
LinkedListDemo[]
。它是否可以重新定义,因为它本身包含类型参数,而S和T本身就是类型参数?谢谢-@VictorAlvarez它是可修改的,因为它本身不是泛型类型参数或类型参数。泛型类型参数被删除,例如
LinkedListDemo[]
LinkedListDemo[]
LinkedListDemo[]
。类型参数被擦除,例如,
S
Object
@VictorAlvarez当发生类型擦除时,适当的强制转换被添加到编译的字节码中。因此,给定
类c
,它将擦除到
类c
,代码
MyType obj=c.newInstance()编译成类似于
MyType obj=(MyType)c.newInstance()的东西(字节码除外)。有关更多信息,请参阅本文:。