Possible Duplicate:
Why is List<Number> not a sub-type of List<Object>?
Isn't String
a subtype of Object
in Java?
Then, how come I cannot pass an object of type List<String>
into a function that accepts List<Object>
as a parameter? I can, though, pass such an object into a function that accepts List
as a parameter.
Isn't String a subtype of Object in Java?
Yes it is, but that doesn't make List<String>
a subtype of List<Object>
.
Consider this example:
List<String> l1 = new ArrayList<String>();
List<Object> l2 = l1; // This is a compilation error in real Java
l2.add(new Integer(42));
String oops = l1.get(0);
If (hypothetically) List<String>
was subtype of List<Object>
, then you'd end up assigning a Integer
to a String
variable in the last statement. In short, we would have broken static type safety.
I can, though, pass such an object into a function that accepts List as a parameter.
Yes, that is true. But then you are dealing with raw types and you have to use explicit type casts when pulling objects out of the list. For example, the above would need to be rewritten as follows:
List<String> l1 = new ArrayList<String>();
List l2 = l1;
l2.add(new Integer(42));
String oops = (String) l1.get(0);
Note that the type-cast means we've had to replace static type-safety with runtime type-safety. (And, of course, in this case the typecast will fail at runtime because the instance has the wrong type.)
In Java, List<S>
is not a subtype of List<T>
when S
is a subtype of T
. This rule provides type safety.
Let's say we allow a List<String>
to be a subtype of List<Object>
. Consider the following example:
public void foo(List<Object> objects) {
objects.add(new Integer(42));
}
List<String> strings = new ArrayList<String>();
strings.add("my string");
foo(strings); // this is not allow in java
// now strings has a string and an integer!
// what would happen if we do the following...??
String myString = strings.get(1);
So, forcing this provides type safety but it also has a drawback, it's less flexible. Consider the following example:
class MyCollection<T> {
public void addAll(Collection<T> otherCollection) {
...
}
}
Here you have a collection of T
's, you want to add all items from another collection. You can't call this method with a Collection<S>
for an S
subtype of T
. Ideally, this is ok because you are only adding elements into your collection, you are not modifying the parameter collection.
To fix this, Java provides what they call "wildcards". Wildcards are a way of providing covariance/contravariance. Now consider the following using wildcards:
class MyCollection<T> {
// Now we allow all types S that are a subtype of T
public void addAll(Collection<? extends T> otherCollection) {
...
otherCollection.add(new S()); // ERROR! not allowed (Here S is a subtype of T)
}
}
Now, with wildcards we allow covariance in the type T and we block operations that are not type safe (for example adding an item into the collection). This way we get flexibility and type safety.
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