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

后端 未结 4 1431
逝去的感伤
逝去的感伤 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:42

    There are a few points that should also be added

    1. At runtime List, List, List and List are all identical. The generic parameter is not compiled at all. All the magic with generics is all compile time fun. This also means that if you have a List that is empty you have no idea what the generic parameter is!

    2. Try not to think of the generic parameter as a "Subtype", the generic parameter really means "the class uses a generic parameter" so in this case "the list uses a Number". A good example of this is the HashMap source, if you have a look into the inner workings of it, it is actually storing an array of Entry, and the entries all have keys and values stored on them. When you look at more complex uses of generics you occasionally see this sort of use.

      In the situation of a List the generic parameter means that the list stores that type of object, it could be that the object never stores an object of the type of the generic parameter at all! Like this:

      public class DummyIterator implements Iterator{
          public boolean hasNext() {
              return false;
          }
      
          public O next() {
              return null;
          }
      }
      
    3. What does List actually mean? Well it is pretty much the same as List for most uses. Keep in mind though that by saying ? you are pretty much saying 'I don't care about the type' which shows itself in this situation:

      List doubles = new ArrayList();
      List numbers = doubles;
      numbers.add(new Double(1));  //COMPILE ERROR
      Number num = numbers.get(0);
      

      So we can't add a Double to a . But for this example:

      List doubles = new ArrayList();
      List numbers = doubles; //COMPILE ERROR
      numbers.add(new Integer(1));
      Number num = numbers.get(0);
      

      You can't assign the List to a List which makes sense as you are specifically telling it, that lists use only Number types

    4. So where should you use a ?? well really anywhere you could say "I don't care about the generic parameter" so for instance:

      boolean equalListSizes(List list1, List list2) {
        return list1.size() == list2.size();
      }
      

      You would use the ? extends Number type of format only where you are not modifying the object using the generic parameter. so for instance:

        Number firstItem(List list1) {
          return list1.get(0);
        }
      
    5. Instead of using the ? and ? extends Number formats try using generics on the class / method instead, in most cases it makes your code more readable as well!:

       T firstItem(List list1) {
        return list1.get(0);
      }
      

      Class:

      class Animal{}
      class Dog extends Animal{}
      class AnimalHouse {
          List animalsInside = new ArrayList(); 
          void enterHouse(A animal){
              animalsInside.add(A);
          }
      
          A leaveHouse() {
              return animalsInside.remove(0);
          }
      }
      AnimalHouse ah = new AnimalHouse();
      ah.enterHouse(new Dog());
      Dog rufus = ah.leaveHouse();
      
    6. As a bonus thought around generics you can also parameterise methods to return a particular class. A good example of this is the any() method in junit and the empty list collection:

      Dog rufus = Matchers.any();
      List dogs = Collections.emptyList();
      

      This syntax allows you to specify the return type of an object. Sometimes quite useful to know (makes some casting redundant)!

    7. 提交回复
      热议问题