简体   繁体   中英

Java Generic type : difference between List <? extends Number> and List <T extends Number>

Java Generic type : what is the difference between

(1) List <? extends Number>   
(2) List <T extends Number>

as per my understanding

(1) List <? extends Number> List <? extends Number> is the Readonly List of "unknown" data type with super class "Number". we can read the element only but can not add

(2) List <T extends Number> List of data type with super class "Number". we can read and add the elements into the list

Please see the below code example

class TestGen{

    public static void main(String[] args) {
        double result = 0.0;

        List<Integer> intList = new ArrayList<Integer>();
        intList.add(10);
        intList.add(20);
        intList.add(30);

        result = TestGen.sumOfList1(intList);
        System.out.println("Result=" + result);
        result = TestGen.sumOfList2(intList);
        System.out.println("Result=" + result);
    }

    public static double sumOfList1(List<? extends Number> list) {
        double s = 0.0;
        for (Number n : list)
            s += n.doubleValue();
        return s;
    }

    public static <T extends Number> double sumOfList2(List<T> list) {
        double s = 0.0;

        // getting error while trying to add new element 
        // list<T> is not applicable for argument(Integer) : Why ?
        list.add(new Integer(40));

        for (Number n : list)
            s += n.doubleValue();

        return s;
    }
}

When I am trying to add the Integer (or even Number object) into the sumOfList2 then getting the error. Please explain what is wrong here ?

Basic difference is if you use T extends Number then you can refer to the type T :
list.add((T) new Integer(40));

Where as if you use ? extends Number ? extends Number then you can not refer to the type, but you can still say:
((List<Integer>)list).add((int) s);

In isolation, there isn't much difference. However, two instances of List<? extends Number> List<? extends Number> in a single context are completely unrelated, while two instances of List<T extends Number> in a single context refer to the same T and the same interface.

public void addAll(List<? extends Number> to, List<? extends Number> from) {
    for (Number n: from) {
        to.add(n);
    }
}

This method fails because n can't be added to to , and also failed because the member types of from and to can be completely different.

public <T> void addAll(List<T extends Number> to, List<T extends Number> from) {
    for (T n: from) {
        to.add(n);
    }
}

This method compiles fine. It isn't necessary; Collections has a better version, but it will run without error.

In sumOfList2 , T is a specific subclass of Number , but it can be any of them. For example T could be BigDecimal , and you can't add an Integer to a List<BigDecimal> .

If you want to be able to add any types of number to the list, it has to be a List<Number> :

public static double sumOfList2(List<Number> list) {...}

The first case is very simple and its known from T extends Number That T is an Object which is of type Number class or its child. This means if we have a method that uses T as a type of Number we can manipulate our method accordingly ie

<T extends Number> void myMethod ( List <T> num){
     num.add(1); // 1 is an Integer
     num.add(2.3) // 2.3 is a Double
} 

But in this *Wild character '?'* case we don't know what kind of Object is going to be referenced even though if it extends Number, but it can be any kind of Object

void myMethod( List <? extends Number> num){
     // num.add(1); // not a valid statement, as we dont know if '1' is of the type '?'
     // num.add(2.3)  // not a valid statement, as we dont know if '2.3' is of the type '?'
}

So the only value that can be written down in such statements is null , as any type of Object can be null.

    void myMethod( List <? extends Number> num){
      num.add(null)
    }

Such methods are Read Only methods.

1)

List <? extends Number> 

It would be appropriate to use

List<Integer> list = Arrays.asList(0,1,2,3,4);

Which does not throw you an error.

List <Double> list = Arrays.asList(0.0,0.1,0.2,0.3,0.4);

then you can add it to

result = TestGen.sumOfList1(list);

2) List

List<Integer> list = new ArrayList<Integer>();
list.add(0);
list.add(1); Would do the job.

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