Reputation: 10093
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
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
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
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
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