开发者

Generics (List) typing question

I am trying to use a common technique to create objects from Xml. (Xml is legacy, so although there are already libraries to do this, it seemed faster to write this myself.)

I don't understand the compiler's complaint about the generic usage. Code sample:

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

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

private void parseObj开发者_开发技巧ectsToList(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 */

}

Thanks for any enlightenment on the subject!


The problem you are running into is that, with the bounded wildcard that you have defined, you will be unable to add any element to the collection. From this tutorial:

List<? extends Shape > is an example of a bounded wildcard. The ? stands for an unknown type, just like the wildcards we saw earlier. However, in this case, we know that this unknown type is in fact a subtype of Shape. (Note: It could be Shape itself, or some subclass; it need not literally extend Shape.) We say that Shape is the upper bound of the wildcard.

There is, as usual, a price to be paid for the flexibility of using wildcards. That price is that it is now illegal to write into shapes in the body of the method


All a wildcard type means is that the actual type parameter T of the List that you pass as the second argument to parseObjectsToList is going to be a subtype of Object. It does NOT mean that the same List will be parameterized with different types.

So now you have a List<T> (called targetList) and you are trying to call targetList.add(Object). This is illegal because Object is not necessarily a subtype of T.

Because you are adding to the List rather than extracting elements from it, use List<Object> and make sure that's exactly what you pass in.


Using a List<Object> will work, but you might want keep your more precisely typed List<Object1> and List<Object2> for type-safety elsewhere. In that case, you'll need to check the type of each object before adding it to the 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))  ;
}

The cast() operation is a reflective equivalent to the static cast operator: (T) newObj

Using the altered method would look something like this:

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


Think about what you are asking the compiler to do:

  1. Given a list of "something that is a subtype of Object
  2. Let me insert an Object into it

This doesn't make sense. Suppose your list is a list of Integer. Suppose that createObjectFromXml returns a String. It wouldn't make sense to allow inserting a String into a list typed for Integers.

So, your options are either to make your List a List<Object> or to find some way to make createObjectFromXml return a specific type, that you can then tie to the type of your list.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜