在 Java 中转换泛型列表

2022-09-03 04:36:54

在铸造泛型时,我发现了一个奇怪的情况。我运行此代码:

class A { }

class B { }

public class Program {

    @SuppressWarnings("unchecked")
    public static void main(String[] args) {
        List<A> listA = new ArrayList<A>();
        List<?> list = listA;
        ((List<B>)list).add(new B());

        for (Object item : listA) {
            System.out.println(item.toString());
        }
    }
}

它编译得很好(只有警告但没有错误),并且没有任何异常运行,输出是:

B@88140ed

我是怎么做到的?我的意思是为什么Java允许我做这样的事情?我已将类的实例添加到 s 列表中?BA

这是泛型非常糟糕的行为。为什么会发生这种情况?

顺便说一句,我用Java 7尝试过。

编辑:
令我惊讶的是,Java只通知问题,并警告每个程序员都可以忽略它。我知道这是个坏主意,但是为什么Java没有否认这种错误或异常的行为呢?SuppressWarnings

此外,此警告始终显示,如果您认为您的选角是正确的,则别无选择,只能忽略它。但是,如果您认为这是好的选角并忽略它,但事实并非如此?


答案 1

每一种编程语言都允许你把自己射中脚

在这种情况下,Java处于两难境地:它可以将泛型信息保留在字节码中,并破坏数百万行现有代码,或者在编译器尽最大努力检查并保持向后兼容性之后静默地删除泛型信息。

Java团队决定采用后者,并引入了Type Erasure - 它有其缺陷。但是,如果他们打破了数百万行完全精细(如果类型不完整)的Java代码行,人们就会带着干草叉和燃烧的火炬出现......


答案 2

您已经通过强制转换和抑制警告击败了 Java 编译时检查。

请注意,由于类型擦除,您创建的列表(在幕后)是一个简单的不类型列表,并且不包含有关要放入其中的内容的运行时检查或断言。


推荐