java在列表中添加false类型时没有异常
在将类类型添加到列表中的过程中,我发现(就我所知)一个奇怪的行为
我有一个列表,其中包含抽象类List<Class<MyAbstractClass>> myImplementations
的所有实现类。我添加了一个非派生类的类型,没有错误。有人能解释一下为什么我可以毫无例外地做myImplementations.add(SomeOtherClass.class);
这样的事情吗?第二个泛型类型(MyAbstractClass)似乎没有任何效果
---编辑---
public abstract class MyAbstractClass{
public static String getMyIdentification(){ throw new RuntimeException("implement method");}
}
public class MyImplementation extends MyAbstractClass{
public static String getMyIdentification(){ return "SomeUUID";}
}
public class OtherClass{}
// in another class:
List<Class<MyAbstractClass>> myImplementations = new ArrayList<Class<MyAbstractClass>>();
myImplementations.add(MyImplementation.class); // does not cause any error
myImplementations.add(OtherClass.class); // does not cause any error, but should in my opinion??
----编辑结束---
谢谢,, 埃尔
# 1 楼答案
使用eclipse编译器时,其行为与预期一致:
也就是说,编译器只对第二次添加进行投诉。但是,如果它通过编译,列表将被转换为原始列表,直到从列表中取出元素(例如使用foreach循环)后才会出现异常
如果没有
? extends
,即使对于String
,编译也会失败。应该是这样的。我很惊讶您没有任何错误,因为java泛型是不变的——也就是说,您不能将Subclass
实例添加到List<Superclass>
# 2 楼答案
关于类型擦除
Java的泛型是非具体化的。A
List<String>
和AList<Integer>
在编译时是不同的类型,但在运行时这两种类型都被删除为List
。这意味着,通过绕过编译时检查,您可以在运行时将Integer
插入List<String>
,这本身可能不会生成ClassCastException
。下面是一个例子:请注意,您必须故意绕过编译时检查,以违反泛型类型不变量:编译器将尽最大努力确保
List<String>
确实只包含String
,并将根据需要生成尽可能多的警告和错误来执行此操作在已检查的集合上
有时我们希望在运行时强制执行类型安全。对于大多数情况,来自^{} 的选中集合包装器可以促进这种行为。从文件中:
以下是对前一段的修改:
注意,作为一种“奖励,
Collections.checkedList
会在运行时抛出NullPointerException
,试图add(null)
在
Class.isAssignableFrom
不幸的是
Collections.checkedList
不支持我们在这个场景中想要的行为:您可以使用它来确保在运行时只能添加java.lang.Class
实例,但它不能确保给定的Class
对象是另一个Class
的子类幸运的是^{} 方法允许您进行此检查,但您必须编写自己的
List
检查包装来执行此检查。这里用static
助手方法而不是完整的List
实现来说明这个想法:现在我们有:
# 3 楼答案
该类型在编译期间被删除,因此在运行时不会看到任何异常。编译器应该对您的情况进行投诉或发出警告
类型参数
Class<String>
在编译过程中被删除——它只被编译器用来检查java源代码是否有效。编译后的字节码不再包含这些信息,在字节码级别,列表将保存并接受Object
或Object
的任何子类。因为Integer.class
是Object
的子类,所以代码将一直运行,直到运行时向程序员抛出ClassCastException,因为它需要Class<String>
实例