如何根据列表的最后一个节点(未知类型)创建一个对象并添加到列表的最后一个?

时间:2011-05-14 17:38:46

标签: java list generics

我尝试下面这样的事情,但编译器警告我这种类型不适用于参数...我知道它不是类型安全的,但是还有其他方法吗?

public void addRow(List<? extends Car> list){
    list.add( list.get(list.size()-1).getClass().newInstance() );

}

3 个答案:

答案 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()的参数是?扩展   形状 - 形状的未知子类型。   因为我们不知道它是什么类型,   我们不知道它是否是超类型   长方形;它可能会也可能不会   这样的超类型,所以它是不安全的   在那里传递一个矩形。

我的建议是重写你提供的方法签名