使用Java编译泛型列表

nro*_*fis 16 java generics wildcard

我在铸造仿制药时发现了一种奇怪的情况.我运行这段代码:

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());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

乙@ 88140ed

我是怎么做到的?我的意思是为什么Java允许我做这样的事情?我BAs 列表中添加了一个类实例?

这是非常糟糕的泛型行为.为什么会这样?

顺便说一下,我用Java 7尝试过.

编辑:
让我感到惊讶的是,Java只通知问题,并警告每个程序员都可以忽略它.我知道这SuppressWarnings是个坏主意,但为什么Java没有拒绝这样的错误或异常行为?

此外,这个警告始终显示,如果你认为你的演员是正确的,你别无选择,只能忽略它.但是,如果你认为这是好的铸造并忽略它但不是吗?

Aar*_*lla 19

每种编程语言都可以让你自己动手.

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

Java团队决定采用后者并引入了类型擦除 - 这有其缺陷.但如果他们打破了数以百万计的完美无缺(如果类型不完整)的Java代码行,人们就会出现干草叉和火炬......

  • "人们会出现干草叉和燃烧的火炬"......那么为什么当C#中加入了类型安全的仿制品时,它们会不会出现?=) (2认同)
  • @ Mints97:我不确定.我的猜测是他们没有相同数量的遗留代码,或者他们可能并不关心.让我们不要忘记Windows上的软件开发人员更多......平均而言......宽大;-) (2认同)
  • @ Mints97:他们*可以*这样做,如果失去Java的最大价值,可用的第三方库的数量无关紧要.Generics的引入方式允许在使用泛型的应用程序中使用现有(未经改编的)库.你假设通过查看一个可能被高估的属性,C#的解决方案更好.没有完整的*差异*可能会伤害更多.此外,拥有一个真正强制的Generic类型系统意味着即使像`Collections.emptyList()`之类的简单事情也不起作用; 它需要每个类型参数的新实例. (2认同)

Bri*_*new 7

您通过强制转换和抑制警告来破坏Java编译时检查.

请注意,由于类型擦除,您创建的列表(在封面下)是一个简单的类型 - 不知道的列表,并且不包含运行时检查或断言,因为您将其放入其中.