Is List a subtype of List<? extends Number> and why?

后端 未结 4 1353
逝去的感伤
逝去的感伤 2021-02-05 18:37

Here is what I know:

  1. Double is a subtype of Number and List is not a subtype of List
4条回答
  •  温柔的废话
    2021-02-05 18:49

    It helped me to see generics as constraints or contracts, not as types with subtypes. So a variable List var says: var is a list of some unknown type ?, which is constrained to be a subtype of Number.

    List listN;
    List listD;
    List listX;
    ...
    Number n1 = ...;
    Double d1 = ...;
    ...
    listN.add(n1); // OK n1 is a Number
    listN.add(d1); // OK d1 is a Double, which is a Number
    listD.add(n1); // compile error, n1 is not a Double
    listD.add(d1); // OK
    listX.add(n1); // compile error, because the exact type of list is not known! (prevents putting a Dog in a Cat list)
    listX.add(d1); // compile error, same cause
    

    So when you can't even put a Number into a List, whats the purpose of such a list? It allows you to work with lists of which the exact type does not matter for the task at hand:

    // instead of several exactly typed methods...
    int count(List numberList) {...}
    int count(List objectList) {...}
    // ...etc. you can have one with a degree of freedom:
    int count(List anyList) {...} // don't need to know the exact type of list
    
    // instead of this...
    Number sum(List numberList) {...}
    Number sum(List doubleList) {...}
    Number sum(List integerList){...}
    // you can do this, with a little less freedom in the ?
    Number sum(List list) {
      // the only thing we need to know about the list's type is that it is some number type
      ...
      Number ni = list.get(i);
      ...
    }
    
    
    

    Using wildcards ? extends X allows to relax rigid contracts to weaker conditions.

    Using a named type parameter, you can establish constraints on allowed types between several variables:

    // works for any type T of list, whatever T is
    // T is the same in the argument and in the return
     T pickObject(List list, int index) {
      return list.get(index);
    }
    
    // works for any type T of list, if T is a Number type
    // T is the same in the argument and in the return
     T pickNumber(List list, int index) {
      return list.get(index);
    }
    ...
    List list;
    Number n = pickNumber(list);
    

    提交回复
    热议问题