我尝试下面这样的事情,但编译器警告我这种类型不适用于参数...我知道它不是类型安全的,但是还有其他方法吗?
public void addRow(List<? extends Car> list){
list.add( list.get(list.size()-1).getClass().newInstance() );
}
答案 0 :(得分:1)
要查看问题,让我们按如下方式扩展有问题的方法:
public <T extends Car> void addRow(List<T> list) throws InstantiationException,
IllegalAccessException {
T element = list.get(list.size() - 1);
Class<T> clazz = element.getClass(); // Compilation Error Here!
T newInstance = clazz.newInstance();
list.add(newInstance);
}
getClass()
返回Class<? extends Car>
。编译器不够聪明,无法知道通配符(?
)是否与T
匹配。程序员可以断言,赋值实际上是安全的:
public <T extends Car> void addRow(List<T> list) throws InstantiationException,
IllegalAccessException {
T element = list.get(list.size() - 1);
@SuppressWarnings("unchecked")
Class<T> clazz = (Class<T>) element.getClass();
T newInstance = clazz.newInstance();
list.add(newInstance);
}
当然,现在类型安全的责任在于程序员。不要忘记,即使它今天可能是安全的,未来的代码更改可能会使断言无效。
答案 1 :(得分:0)
问题是getClass()
的返回类型是Class<?>
。在这种情况下,Java并不足以推断出正确的类型 - 但是你是,所以使用强制转换。
答案 2 :(得分:0)
您的方法声明调用List,其类型是扩展Car的类。然而,当你调用newInstance时,编译器不知道sublcass是什么,因此它也将类确定为Car。好吧,你不能将Car添加到期望Car的子类的List。
如果您的List可以接受存储汽车而不仅仅是子类,为什么不写这样的方法..
public void addRow(List<Car> list) throws Exception {
list.add( list.get(list.size()-1).getClass().newInstance() );
}
从Oracle自己的文档中了解为什么你的方法不起作用......
像往常一样,要付出代价 为了灵活使用 通配符。那个价格是这样的 现在非法写入形状 方法的主体。例如, 这是不允许的:
public void addRectangle(List<?
extends Shape> shapes) {
shapes.add(0, new Rectangle()); // Compile-time error!
}
你应该 能够弄清楚为什么上面的代码 是不被允许的。第二种类型 shapes.add()的参数是?扩展 形状 - 形状的未知子类型。 因为我们不知道它是什么类型, 我们不知道它是否是超类型 长方形;它可能会也可能不会 这样的超类型,所以它是不安全的 在那里传递一个矩形。
我的建议是重写你提供的方法签名