简体   繁体   中英

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> List<? extends Integer> is subtype of List<? extends Number> List<? extends Number> . And we can assign a variable of List<? extends Integer> List<? extends Integer> for a variable of List<? extends Number> 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

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 eg 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> List <? extends Integer> and List <T extends Number> . So the difference IMO is:

  1. List <? extends Integer> 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> List <? extends Number> and not List <? extends Integer> 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> List<? extends Integer> will accept Integer and List<?extends Number> is even more relaxing. The relation between all these is expressed by the image .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM