泛型(列表)输入问题

时间:2010-06-25 17:46:45

标签: java generics reflection

我正在尝试使用常用技术从Xml创建对象。 (Xml是遗留的,所以尽管已经有了这样的库,但我自己写这个似乎更快。)

我不理解编译器对通用用法的抱怨。代码示例:

public void createObjects() {
  List<Object1> objectOnes = new ArrayList<Object1>();
  List<Object2> objectTwos = new ArrayList<Object2>();

  parseObjectsToList("XmlElement1", objectOnes);
  parseObjectsToList("XmlElement2", objectTwos);
}

private void parseObjectsToList(String xmlTag, List<? extends Object> targetList) {
   // read Xml and create object using reflection
   Object newObj = createObjectFromXml(xmlTag);
   targetList.add(newObj)  

/* compiler complains: "The method add(capture#2-of ? extends Object) in the type List<capture#2-of ? extends Object> is not applicable for the arguments (Object)" 
*/

/* If I change method signature to parseObjectsToList(String xmlTag, List targetList)
it works fine, but generates compiler warning about raw type */

}

感谢您对此主题的任何启发!

4 个答案:

答案 0 :(得分:4)

您遇到的问题是,使用您定义的有界通配符,您将无法向集合中添加任何元素。来自this tutorial

  

List<? extends Shape >是有界通配符的示例。的?代表一种未知类型,就像我们之前看到的通配符一样。但是,在这种情况下,我们知道这种未知类型实际上是Shape的子类型。 (注意:它可能是Shape本身,或者是某些子类;它不需要字面上扩展Shape。)我们说Shape是通配符的上限。

     

像往常一样,使用通配符的灵活性需要付出代价。 这个价格是在方法正文中写入形状现在是非法的

答案 1 :(得分:2)

所有通配符类型都意味着您作为T的第二个参数传递的List的实际类型参数parseObjectsToList将成为{{1}的子类型}。这并不意味着相同的Object将使用不同的类型进行参数化。

现在您有一个List(名为List<T>),您正试图致电targetList。这是非法的,因为targetList.add(Object)不一定是Object的子类型。

因为您要添加T而不是从中提取元素,所以请使用List并确保这正是您传入的内容。

答案 2 :(得分:1)

使用List<Object>会有效,但您可能希望更精确地键入List<Object1>List<Object2>以确保其他地方的类型安全。在这种情况下,您需要在将每个对象添加到List之前检查每个对象的类型。

private void parseObjectsToList(String tag, List<T> list, Class<? extends T> c) {
   // read Xml and create object using reflection
   Object newObj = createObjectFromXml(tag);
   list.add(c.cast(newObj))  ;
}

cast()操作是静态强制转换操作符的反射等价物:(T) newObj

使用改变的方法看起来像这样:

parseObjectsToList("XmlElement1", objectOnes, Object1.class);

答案 3 :(得分:1)

想想你要求编译器做什么:

  1. 给出一个“Object
  2. 子类型的列表
  3. 让我在其中插入Object
  4. 这没有意义。假设您的列表是Integer的列表。假设createObjectFromXml返回String。允许将String插入为Integers键入的列表中是没有意义的。

    因此,您可以选择将列表设为List<Object>,或者找到某种方法使createObjectFromXml返回特定类型,然后您可以将其与列表类型绑定。