List> vs List<? extends Map>

前端 未结 5 666
谎友^
谎友^ 2020-12-04 05:45

Is there any difference between

List>

and

List>
<         


        
5条回答
  •  一生所求
    2020-12-04 05:54

    What I'm missing in the other answers is a reference to how this relates to co- and contravariance and sub- and supertypes (that is, polymorphism) in general and to Java in particular. This may be well understood by the OP, but just in case, here it goes:

    Covariance

    If you have a class Automobile, then Car and Truck are their subtypes. Any Car can be assigned to a variable of type Automobile, this is well-known in OO and is called polymorphism. Covariance refers to using this same principle in scenarios with generics or delegates. Java doesn't have delegates (yet), so the term applies only to generics.

    I tend to think of covariance as standard polymorphism what you would expect to work without thinking, because:

    List cars;
    List automobiles = cars;
    // You'd expect this to work because Car is-a Automobile, but
    // throws inconvertible types compile error.
    

    The reason of the error is, however, correct: List does not inherit from List and thus cannot be assigned to each other. Only the generic type parameters have an inherit relationship. One might think that the Java compiler simply isn't smart enough to properly understand your scenario there. However, you can help the compiler by giving him a hint:

    List cars;
    List automobiles = cars;   // no error
    

    Contravariance

    The reverse of co-variance is contravariance. Where in covariance the parameter types must have a subtype relationship, in contravariance they must have a supertype relationship. This can be considered as an inheritance upper-bound: any supertype is allowed up and including the specified type:

    class AutoColorComparer implements Comparator
        public int compare(Automobile a, Automobile b) {
            // Return comparison of colors
        }
    

    This can be used with Collections.sort:

    public static  void sort(List list, Comparator c)
    
    // Which you can call like this, without errors:
    List cars = getListFromSomewhere();
    Collections.sort(cars, new AutoColorComparer());
    

    You could even call it with a comparer that compares objects and use it with any type.

    When to use contra or co-variance?

    A bit OT perhaps, you didn't ask, but it helps understanding answering your question. In general, when you get something, use covariance and when you put something, use contravariance. This is best explained in an answer to Stack Overflow question How would contravariance be used in Java generics?.

    So what is it then with List>

    You use extends, so the rules for covariance applies. Here you have a list of maps and each item you store in the list must be a Map or derive from it. The statement List> cannot derive from Map, but must be a Map.

    Hence, the following will work, because TreeMap inherits from Map:

    List> mapList = new ArrayList>();
    mapList.add(new TreeMap());
    

    but this will not:

    List> mapList = new ArrayList>();
    mapList.add(new TreeMap());
    

    and this will not work either, because it does not satisfy the covariance constraint:

    List> mapList = new ArrayList>();
    mapList.add(new ArrayList());   // This is NOT allowed, List does not implement Map
    

    What else?

    This is probably obvious, but you may have already noted that using the extends keyword only applies to that parameter and not to the rest. I.e., the following will not compile:

    List> mapList = new List>();
    mapList.add(new TreeMap())  // This is NOT allowed
    

    Suppose you want to allow any type in the map, with a key as string, you can use extend on each type parameter. I.e., suppose you process XML and you want to store AttrNode, Element etc in a map, you can do something like:

    List> listOfMapsOfNodes = new...;
    
    // Now you can do:
    listOfMapsOfNodes.add(new TreeMap());
    listOfMapsOfNodes.add(new TreeMap());
    

提交回复
热议问题