27

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> 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 ?

5 Answers 5

29

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 then you can not refer to the type, but you can still say:
((List<Integer>)list).add((int) s);

Sign up to request clarification or add additional context in comments.

3 Comments

Not sure who down voted....this solution works, can you please shed a light why casting is required. list.add((T) new Integer(40)); while we are adding the object of sub class only (Integer is subclass of Number)
I'm guessing it gives you the type safety warning, when you cast it to T.
I guess, as per the type of argument, List can accept values of type T, and hence you need to cast the argument to add() to T
13

In isolation, there isn't much difference. However, two instances of 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.

1 Comment

In fact addAll(List<T extends Number> to, ... doesn't even compile. It needs to be <T extends Number> void addAll(List<T> to, ...
1

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) {...}

Comments

0

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 i.e

<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 Comment

your first sample can not be compiled actually.
0

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.