Possible Duplicate:
java generics covariance
I am trying to make sense of the fact that List<String>
is not a subtype of List<Object>
.
In effective Java, Josh Bloch notes that although it may seem counter-intuitive,it does make sense. The reason he stated is that you can put any Object in List<Object>
, but can only put String in List<String>
. I am not sure how this justifies why the String list is not a subtype of Object list.
Maybe I am confused by the term subtype
. What I think it means is that when S is a subtype of T, an instance of S is an instance of T. Therefore, for List<String>
to be a subtype of List<Object>
, Object has to be a super class of String, which it technically is. Any idea where my reasoning went wrong?
List<String> isn't type related to List<Object> in any way, not anymore than List<String> is related to List<Number> . The type is List<String> , the entire signature is the type . But like with everything, there are exceptions; these are called Wildcard Parameterized Types .
String is a subtype of Object , because the String class is a subclass of the Object class. int is not a subtype of Object , because none of Java's primitive types are subtypes of any reference type.
Although Integer is a subtype of Number, List<Integer> is not a subtype of List<Number> and, in fact, these two types are not related.
So ArrayList<String> is a subtype of List<String>, which is a subtype of Collection<String>. So long as you do not vary the type argument, the subtyping relationship is preserved between the types.
List<String> s = new ArrayList<String>();
List<Object> o = s;
o.add(new Object());
String first = s.get(0); // boom
This goes back to what it means for A
to be a subtype of B
. The formal name for this is the Liskov substitution principle, which says basically that A
is a subtype of B
if and only if you can take any valid program that has in it something of type B
, swap in something of type A
and it would still be a valid program. The effect of this is that if you can use an A
wherever you could use a B
, then A
is a subtype of B
.
So in this case, since this is part of a valid (valid meaning "compiling") program:
public static void doThing(List<Object> x) {
x.add(new Object());
}
Then, by the Liskov substitution principle, if List<String>
were a subtype of List<Object>
this would be part of a valid program too:
public static void doThing(List<String> y) {
y.add(new Object());
}
But clearly that second snippet can't compile. Therefore, that second snippet is not part of a valid program, and therefore List<String>
is not a subtype of List<Object>
.
Likewise, the other way around is also not true: List<Object>
is not a subtype of List<String>
. Finding the program snippet to prove that is left as an exercise for the reader.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With