Card 04/ 09
Why a List<String> Is Not a List<Object>
A String is an Object, and still the compiler refuses to pass a list of strings as a list of objects.
Even though every String is an Object, a List<String> cannot be passed where a List<Object> is expected. Allowing it would let the receiving code add a non-string to a list that promised to hold only strings.
A method that takes a List<Object> refuses a List<String>, which reads like an inconsistency:
Report.java:8: error: incompatible types: List<String> cannot be converted to List<Object>Imagine it were allowed. The method would believe it held a list of objects, and nothing would stop this:
void spoil(List<Object> anything) {
anything.add(42);
}
List<String> refs = new ArrayList<>();
spoil(refs);
String first = refs.get(0);Line 2 is legal for a list of objects. Line 8 would then fail with a ClassCastException on a list whose declaration promised it held only strings, which is exactly the failure generics exist to remove.
The rule has a name, invariance: a generic type with one type argument is unrelated to the same type with another, whatever the relationship between the two arguments.
When a method only reads, say so with a wildcard, a ? that stands for some type you do not name: List<? extends Object>, usually written List<?>. That accepts a list of anything and refuses to add to it, which is the combination that makes it safe.
← → move through sections and cards