11

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**
Razvan
  • 9,925
  • 6
  • 38
  • 51
  • 4
    Can you show how you are defining them previously for your second example? – Quetzalcoatl Apr 03 '13 at 10:04
  • @SaurabhAgarwal isn't that the point? Why does "any subclass" work but a _specific_ subclass doesn't ? – Alnitak Apr 03 '13 at 10:05
  • public class WildcardsTest {/* code presented above in 2 */} – Razvan Apr 03 '13 at 10:06
  • I wonder if it has anything to with Integer being final, Eclipse comes up with the following warning when I implement your code: "The type parameter U should not be bounded by the final type Integer. Final types cannot be further extended" – Quetzalcoatl Apr 03 '13 at 10:14
  • @Quetzalcoatl: this doesn't work either class A{} class B extends A{} public class WildcardsTest{/* code presented above in 2 */} – Razvan Apr 03 '13 at 10:20
  • To clarify, are `U` and `S` type parameters or classes? – Paul Bellora Apr 03 '13 at 14:23
  • @PaulBellora: U and S are type parameters in a generic class _declaration_. – Razvan Apr 03 '13 at 14:40
  • @Razvan Okay, check out [my answer](http://stackoverflow.com/a/15790682/697449) and let me know if there's any further confusion. – Paul Bellora Apr 03 '13 at 14:51

4 Answers4

3

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;
Community
  • 1
  • 1
Paul Bellora
  • 54,340
  • 18
  • 130
  • 181
1

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;
OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
-1

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

Saurabh Agarwal
  • 323
  • 2
  • 6
  • 16
-2

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.

Saurabh Agarwal
  • 323
  • 2
  • 6
  • 16