Nam
Nam

Reputation: 56

Subtype of generic type in java

I am confusing about the subtype of generic in java. I have a sample below.

public class Class2{

    public static <T extends Number> void set(List<T> list){
        List<T> numberList = list;;

    }

    public static <T extends Integer> List<T> get(){
        List<T> list = new ArrayList<T>();
        return list;
    }
}
//Does this line is the same as the two below line?
Class2.set(Class2.get());

List<? extends Integer> intList = new ArrayList<>();
List<? extends Number> numberList = intList;

My question: what is different between

Class2.set(Class2.get());

and

List<? extends Integer> intList = new ArrayList<>();
List<? extends Number> numberList = intList;

UPDATE #1: change

 public static <T> void set(List<T> list)

to

 public static <T extends Number> void set(List<T> list)

UPDATE #2: Look at the image (took from docs.oracle about generic in java) Link:https://docs.oracle.com/javase/tutorial/figures/java/generics-wildcardSubtyping.gif

From the image we know that List<? extends Integer> is subtype of List<? extends Number>. And we can assign a variable of List<? extends Integer> for a variable of List<? extends Number>.

In my example above, do I really assign a variable of List<T extends Integer> for a variable of List<T extends Number>? If so, is List<T extends Number> is subtype of List<T extends Integer>? Can you guy so me how to prove that if it is or not? P/S: Link post of oracle docs : https://docs.oracle.com/javase/tutorial/java/generics/subtyping.html

Upvotes: 2

Views: 4747

Answers (1)

akhil_mittal
akhil_mittal

Reputation: 24157

The method set in class2 takes a list where all elements are of type T and T is Number or any sub class of Number:

public static <T extends Number> void set(List<T> list){
        List<T> numberList = list;

}

This will assign the input parameter list to numberList and both can contain element of only one type which is represented by T(T needs to be Number or subtype of Number e.g. Integer).

On the other hand method get will return a list of element where each element is of type T and <T extends Integer> means T has to be Integer or one of the subclass of Integer. We need to understand that this T is not same as the one defined in method set above.

Now the following line:

Class2.set(Class2.get());

actually initializes numberList with elements where each element is of same type T. On the other hand we have:

List<? extends Integer> intList = new ArrayList<>();

The confusion seems to narrow down between: List <? extends Integer> and List <T extends Number>. So the difference IMO is:

  1. List <? extends Integer> means it is a list of "unknown type" which will extend Integer and as per the rule PECS(Producer Extends Consumer Super) this can produce elements but can not consume elements.
  2. List<T extends Integer> is a list of type with super class Integer and we can read or add the elements into the list.

    On a side note the signature should have been List <? extends Number> and not List <? extends Integer> as Integer is final and cannot be sub-classed.

Using extends

List<? extends Number> list1 = new ArrayList<Number>();  // Number "extends" Number (in context)
List<? extends Number> list2 = new ArrayList<Integer>(); // Integer extends Number
List<? extends Number> list3 = new ArrayList<Double>();  // Double extends Number

Using super

List<? super Integer> list4 = new ArrayList<Integer>();  // Integer is a "superclass" of Integer
List<? super Integer> list5 = new ArrayList<Number>();   // Number is a superclass of Integer
List<? super Integer> list6 = new ArrayList<Object>();   // Object is a superclass of Integer

EDIT:

The method get returns a list of elements with type T (T can be Integer or subtype):

List<Integer> list1 = Class2.get();

Now for the set method all the following will work:

List<Integer> list1 = Class2.get();
Class2.set(list1);
List<Number> list2 = new ArrayList<Number>();
Class2.set(list2);
List<Integer> list3 = new ArrayList<Integer>();
Class2.set(list3);

As mentioned in doc

Integer is a subtype of Number but List<Integer> is not subtype of List<number>, rather these are not related at all. The common parent of List<Number> and List<Integer> is List<?>.

As I explained above List<? extends Integer> will accept Integer and List<?extends Number> is even more relaxing. The relation between all these is expressed by the image.

Upvotes: 1

Related Questions