Java泛型,来自C++;模板

Java泛型,来自C++;模板,java,generics,Java,Generics,我发现以下代码在Java中非常出色: ArrayList<String> l1 = new ArrayList<String>(); ArrayList<Integer> l2 = new ArrayList<Integer>(); System.out.println(l1.getClass() == l2.getClass()); // true System.out.println(l2.getClass().

我发现以下代码在Java中非常出色:

    ArrayList<String> l1 = new ArrayList<String>();
    ArrayList<Integer> l2 = new ArrayList<Integer>();
    System.out.println(l1.getClass() == l2.getClass()); // true
    System.out.println(l2.getClass().isAssignableFrom(l1.getClass())); // true too
    //ArrayList<Integer> l3 = l1; // won't compile though
ArrayList l1=新的ArrayList();
ArrayList l2=新的ArrayList();
System.out.println(l1.getClass()==l2.getClass());//真的
System.out.println(l2.getClass().isAssignableFrom(l1.getClass());//也是这样
//ArrayList l3=l1;//但不会编译
我不太明白“isAssignableFrom”的细节。当然,我希望编译器停止l3=l2,但它似乎与前一行相矛盾?(我确信这里有一些微妙的地方,这就是我想要的:-)

所有的
信息在编译后都会被剥离掉。就字节码而言,它们都是同一个类

在编译过程中,会检查它们的一致性和兼容性

因此,当它检查
l2.getClass().isAssignableFrom(l1.getClass())
时,它会说
ArrayList可从ArrayList赋值吗?
,答案是肯定的。但是,因为在编译期间它仍然有类型信息,所以它是不允许的。

所有的
信息在编译后都会被剥离掉。就字节码而言,它们都是同一个类

在编译过程中,会检查它们的一致性和兼容性

因此,当它检查
l2.getClass().isAssignableFrom(l1.getClass())
时,它会说
ArrayList可从ArrayList赋值吗?
,答案是肯定的。但是因为在编译过程中它仍然有类型信息,所以它是不允许的。

这是由Java的泛型实现(相当草率)造成的,即

基本上,编译器会删除类型信息(例如:
ArrayList
ArrayList
都变成
ArrayList
),并在必要时添加强制转换。在运行时,
l1
l2
之间没有类型区别,但编译器不会让您进行赋值-因为它知道类型是不同的。

这是由Java的泛型实现(相当草率)造成的,即

基本上,编译器会删除类型信息(例如:
ArrayList
ArrayList
都变成
ArrayList
),并在必要时添加强制转换。在运行时,
l1
l2
之间没有类型区别,但编译器不允许您进行赋值-因为它知道类型不同。

这是因为泛型。

这是因为泛型。

isAssignableFrom()正在测试类是否相同,或者如果第二个是第一个的超类或超接口。

正如其他答案所述,泛型在编译时被删除,因此它们对该方法的输出没有影响。只有基类是最重要的

参考:

isAssignableFrom()正在测试这些类是否相同,或者第二个类是否是第一个类的超类或超接口。

正如其他答案所述,泛型在编译时被删除,因此它们对该方法的输出没有影响。只有基类是最重要的


引用:

您想要的可以由
getType()
方法提供,并且
l1.getType()
应该返回
ArrayList
,而
l2.getType()
应该返回
ArrayList


不幸的是,Java在对象上没有
getType()
getClass()
在这两种情况下都返回
ArrayList

您想要的可以通过
getType()
方法来实现,并且
l1.getType()
应该返回
ArrayList
,而
l2.getType()
应该返回
ArrayList


不幸的是,Java在对象上没有
getType()
getClass()
在这两种情况下都返回
ArrayList

既然你发现
l1.getClass()==l2.getClass()
是真的,那么
l2.getClass().isAssignableFrom(l1.getClass())
应该是显而易见的(
x.isAssignableFrom(x)
应该总是真的,不是吗?)。你真正的问题是为什么
l1.getClass()==l2.getClass()
是真的,这是由于擦除。运行时只有一个类。

既然您发现
l1.getClass()==l2.getClass()
是真的,那么
l2.getClass().isAssignableFrom(l1.getClass())
应该是显而易见的(
x.isAssignableFrom(x)
应该总是真的,不是吗?)。你真正的问题是为什么
l1.getClass()==l2.getClass()
是真的,这是由于擦除。运行时只有一个类。

具体来说,这称为类型擦除。关于泛型的Java教程很好地解释了Java泛型的缺陷:是的,感觉有点矛盾,因为有些东西在运行时是真的,但在编译时不是真的,或者,它是可赋值的,但不能赋值。这感觉不太对:-)@Frank我想依赖运行时正确性的心态是糟糕的设计;相反,我们应该设计代码,以便在编译时捕获错误。这并不是说我们总是成功:)当然,我同意这一点。我的主要问题是,阶级是平等的,同时又是不平等的。至于编译时做更多的事情,我喜欢尽可能多地把运行时移到编译时,在C++中(没有机会在java中完成)。在java中,你不能做太多的事情,因为老实说,java能比JIT做得更好。公平地说,它们不是同时相等和不相等,而是在某个时间相等,在另一个时间不相等。具体地说,这称为类型擦除。Java泛型教程非常擅长解释Java泛型的缺陷:是的,感觉有点矛盾,因为有些东西在运行时是正确的,但在编译时不是,或者,它是可赋值的,但是