Razvan
Razvan

Reputation: 10093

Java wildcards vs type parameters

Why does 1 work and 2 not ?

1:

public List<? extends Integer> l1;
public List<? extends Number> l2 = l1;

2:

public List<U> l1;
public List<S> l2 = l1;
//where U and S have been previously defined as: **S extends Number,U extends Integer**

Upvotes: 11

Views: 311

Answers (4)

OldCurmudgeon
OldCurmudgeon

Reputation: 65813

BTW: You cannot extend Integer, Integer is a final class.

// l1 holds any subclass of Integer and, because Integer implements Number it is also a subclass of Number
public List<? extends Integer> l1;
// l1 (see above) implements Number so this is fine.
public List<? extends Number> l2 = l1;

// Using Integer here instead of your U because you cannot extend Integer - it is final.
public List<Integer> l3;
// Make S extend Number
static class S extends Number {
  // Implementing the abstract methods of Number
}
// NOT valid because l4 must be a List of S not a list of ANY Number and l3 is a List<Integer> - no connection other than a commmon interface.
public List<S> l4 = l3;

Upvotes: 1

Paul Bellora
Paul Bellora

Reputation: 55213

Generics are not covariant. For example:

List<Integer> l1;
List<Number> l2;
l1 = l2; // incompatible types
l2 = l1; // also incompatible

However, wildcarded types offer a way to express covariance:

List<? extends Integer> l1;
List<? extends Number> l2 = l1; //legal

l1 is being expressed as a List of some unknown type that is or extends Integer. Similarly, l2 is a List of some type that is or extends Number. Since Integer extends Number, the compiler knows assigning l1 to l2 must be okay.

This situation is different:

<S extends Number, U extends Integer> void someMethod() {

    List<U> l1;
    List<S> l2 = l1; //incompatible types
}

S and U are type parameters, meaning they are provided some specific type arguments by callers of someMethod (or type inferrence). These type arguments could be a concrete type like Integer or a wildcard capture.

While they are also bounded, this is different from using bounded wildcards like above. Type parameters are bounded at declaration - within the method body they are understood not to change. For example, let's say both S and U were resolved to Integer by calling:

this.<Integer, Integer>someMethod();

In this case we can imagine the method body looks like this:

List<Integer> l1;
List<Integer> l2 = l1; // okay why not?

This would be legal, but we just happened to get lucky. There are many situations where it wouldn't be. For example:

this.<Double, Integer>someMethod();

Now we reimagine the method body:

List<Integer> l1;
List<Double> l2 = l1; // danger!

So you can see that a bounded type parameter is a something much different from a bounded wildcard, which allows different generic types to be covariantly "swapped in":

List<Integer> l1;
List<Double> l2;
List<? extends Number> l3;
l3 = l1;
l3 = l2;

Upvotes: 3

Saurabh Agarwal
Saurabh Agarwal

Reputation: 323

Look In 1.1 you are saying any class which extends Integer and in 1.2 any class which extends Number. Now is such a way Integer is sub class of Number that's why it didn't give any error in 1st case. But is 2.1 you are saying only U and in 2.2 only S and you are doing

 public List<S> l2 = l1

and l1 is of type U not S and generics don't supports such object referencing by it's own. You will have to use wild cards like used in 1st case.

 public List<? extends Number> l2 = l1;

Will solve your problem..

Upvotes: -1

Saurabh Agarwal
Saurabh Agarwal

Reputation: 323

Because in 1 you are saying any sub class of the Integer and Number respectively.

But in second you are saying Generic of U and S and like this generics don't supports Super can refer Sub class object concept of java OOP's.

Upvotes: -2

Related Questions