When using generics in a interface method, all other methods of the interface involving list of concrete classes are not being resolved properly.
interface Fruit<T extends Fruit>
{
public List<String> getColors();
public List<T> getChildren();
}
class FruitUtil
{
public static void readFruit(Fruit fruit)
{
// shows error : Type mismatch: cannot convert from element type Object to String
for(String color : fruit.getColors()) { }
// shows error : Type mismatch: cannot convert from element type Object to Fruit
for(Fruit thisFruit : fruit.getChildren()) { }
}
}
Here, though I've used generics to represent the list of children of Fruit
, I have a concrete String
list to represent fruit's colors.
But, when using getColors()
of Fruit
, it is returning List
instead of List<String>
, despite it having the exact return type.
Am I missing anything here?
You are using Fruit
as a raw type, and therefore the return type of any of its methods is treated as the erasure of that type.
So in the following line:
for(String color : fruit.getColors())
The object fruit
is of a raw type and therefore getColors()
returns the erasure, List
, equivalent to List<Object>
. This is specified by the Java Language Specification section on raw types:
The type of a constructor (§8.8), instance method (§8.4, §9.4), or non-static field (§8.3) of a raw type C that is not inherited from its superclasses or superinterfaces is the erasure of its type in the generic class or interface C.
Note that raw types exist to facilitate interfacing with non-generic legacy code written prior to Java 1.5, i.e. more than 20 years ago. They should be avoided. The JLS warns you not to use them:
The use of raw types is allowed only as a concession to compatibility of legacy code. The use of raw types in code written after the introduction of generics into the Java programming language is strongly discouraged. It is possible that future versions of the Java programming language will disallow the use of raw types.
You have raw types in various places in your code. One way to fix them is as follows:
interface Fruit<T extends Fruit<T>>
...
public static void readFruit(Fruit<?> fruit)
...
for(Fruit<?> thisFruit : fruit.getChildren())