Can someone explain to me why the following code does not work?
public class TestGeneric {
EntityManager entityManager = new EntityManager();
public <T extends Textable & Entity> void doAction(T obj) {
entityManager.getAliasForEntityClass(obj.getClass());
}
}
class EntityManager {
public String getAliasForEntityClass(Class<? extends Entity> clazz) {
return clazz.getCanonicalName();
}
}
interface Entity {
Long getId();
}
interface Textable {
String getText();
}
I’m getting the following error:
The method getAliasForEntityClass(Class<? extends Entity>) in the type EntityManager is not applicable for the arguments
(Class<capture#1-of ? extends Textable>)
If I wrote in this way, I did not have any error:
public class TestGeneric {
EntityManager entityManager = new EntityManager();
public <T extends Entity & Textable> void doAction(T obj) {
entityManager.getAliasForEntityClass(obj.getClass());
}
}
class EntityManager {
public String getAliasForEntityClass(Class<? extends Entity> clazz) {
return clazz.getCanonicalName();
}
}
interface Entity {
Long getId();
}
interface Textable {
String getText();
}
Template <T extends Entity & Textable> and <T extends Textable & Entity> means: T must implements Entity and Textable interfaces. Why position of interface so important in this example?
The reason is that the erasure of
Tis the leftmost type in the bound. From thegetClass()documentation:The JLS specifies that “the erasure of a type variable is the erasure of its leftmost bound” (see here). So the type of
obj.getClass()isClass<? extends Textable>in the first case andClass<? extends Entity>in the other.