Search code examples
javaobjectwildcardsubtyping

Is this Java typing hierarchy correct?


Given the types List<?>, List<Object>, List<? super Number>, List<Number>, List<Integer>, and List<? extends Number>, I am trying to understand their hierarchy.

I know that List<Integer> is NOT a subtype of List<Number>, even though Integer is indeed a subtype of Number, so I thought that it was instead a subtype of List<? extends Number>.

But List<? extends Number> intuitively seems to be a subtype of List<Number>, which makes List<Integer> a descendant of List<Number> after all, as my idea of it shows:

enter image description here

So, if a type is descended from another, but not directly, is it still a subtype of its ancestor (or I am just wrong in the diagram)? This exercise has also gotten me a bit confused about ? vs. Object...actually, it looks like I might have List<Object> and List<? super Number> mixed up. I guess one of the biggest questions is, "Is 'everything' an Object...or is everything a ? ?" Or both...or neither?


Solution

  • Reason why List<Integer> is not a sub type of List<Number>.

    lets just consider a scenario where a List<Number> accepts List<Integer>(which would practically wouldn't work).

      List<Integer> listI =new ArrayList<Integer>();
      List<Double>  listD = new ArrayList<Double>();
      method(listI);
      method(listD);
    

    and you have a method which takes List<Number> as an argument.

       public void method(List<Number> list) {
        list.add(new Double()); // would fail if you pass an List<Integer> as Integer is not a super type of Integer.
        list.add(new Integer()); //would fail if you pass an List<Double> as Double is not a subtype of Integer       
        }     
    

    so if your method argument declared as List<number> accepts List<Double> and you try to add an Integer into the list of Double.which is wrong, because Double is not a super type of Integer thus List<Number> is not a sub type List<Integer>.

    now consider the same scenario where List<? extends Number> is a method argument instead of List<Number>

                public void method(List<? extends Number> list) {
                          // list.add(new Double()); 
                          // list.add(new Integer());       
                   }
    

    and now you pass an List<Integer> to this method. if it accepts it and you try to add a Double to list of Integers. BOOM... you just added a Double to List of Integer .

    To give an informal example . consider an Animal supertype with Cat and Dog as subtypes. now, you have a method which accepts <? extends Animal> and you pass an Dog to this method. and in the method you try to add an Cat. its adding a wrong type (a CAT) to your Dog, thus **List<Dog>** is not a subtype of List<? extends Animal>

    please let me know if this is not expressive enough.Thanks :)