我在这里遇到一个关于带有列表的泛型有界类型的小问题。请帮忙!
Model.java
public class Model {
}
ClassA.java
public class ClassA<T extends Model> {
private List<T> models;
public ClassA() {
models.add((T) new Model());
}
}
它在这一行给我一个未经检查的模型到T警告:
models.add((T) new Model());
我理解我收到这个警告是因为我可以安全地从一个子类投射到一个超级类而不是反过来。
有没有办法解决这个问题,还是我可以安全地压制警告?
答案 0 :(得分:9)
你无法做你想做的事。
由于 T 是模型的子类:
具体地:的
如果通过调用 new Model()构造一个新模型,该实例就是一个Model而不是任何子类的实例。
在子类扩展超类的情况下,您永远无法成功执行此操作:
(Subclass) new Superclass();
因此,您无法成功将新模型强制转换为T的实例。
编译器只会给你一个警告,你可以忽略或抑制,但是当你运行你的程序并调用 add() ClassCastException >方法。
答案 1 :(得分:1)
以此为例
public static void main(String[] args) {
ClassA<SubModel> models = new ClassA<>();
for (SubModel model : models.getModels()){
model.run(); // runtime ClassCastException
}
}
public static class ClassA<T extends Model> {
private List<T> models = new LinkedList<>();
public ClassA() {
models.add((T)new Model()); // compiles and warns
}
public List<T> getModels() {
return models;
}
}
public static class SubModel extends Model {
public void run() {
System.out.println(this);
}
}
public static class Model {
}
您添加到models
的对象属于运行时类型Model
,它没有run()
方法。
当您最终尝试将对象用作SubModel
类型的对象时,您将像ClassCastException
方法一样获得main()
。
你真的不应该这样做,即。将父类型对象添加到可能的suptype类型对象。
答案 2 :(得分:-1)
在构造函数中添加元素之前,需要初始化列表。我想你可能只复制了相关的代码片段,这就是为什么它被遗漏了。
另外,我认为唯一的方法是抑制警告。更多信息仅协方差,逆变:Covariance, Invariance and Contravariance explained in plain English?