我想在java中实现这样的东西,但是得到编译时错误:
方法onMessage(TextMessage,Class)中的类型
AbstractTestLoader不适用于参数
(TextMessage,Class)
我理解这个错误的原因,但我也觉得应该有一些方法来实现这一点,或者可能是其他方式。
public abstract class AbstractTestLoader<T extends AbstractEntity<T>> {
public void onMessage(TextMessage message) throws Exception {
onMessage(message, this.getClass()); // I want to correct this line in such a way so that I can call below method with actual Class of {T extends AbstractEntity<T>}
}
public void onMessage(TextMessage message, Class<T> clazz) throws Exception {
//here my original logic will go
}
}
应该注意的是,虽然Java泛型在运行时被擦除,但是如果它们存在于类文件中,则有限的反射apis来检索它们。
以下是这些假设的快速解决方案:
AbstractTestLoader
是超级直接的。
- 在声明超类时,子类不使用类型通配符,例如像这样的子类
class GenericLoader<T extends SubclassAbstractEntity<T>> extends AbstractTestLoader<T>
不存在。
这是代码:
public class AbstractTestLoader<T extends AbstractEntity<T>> {
private static final ClassValue<Class<?>> TYPE_PARAMETER_CACHE = new ClassValue<Class<?>>() {
@Override
protected Class<?> computeValue(Class<?> type) {
assert AbstractTestLoader.class.isAssignableFrom(type);
assert type.getSuperclass() == AbstractTestLoader.class;
Type genericSuperclass = type.getGenericSuperclass();
assert genericSuperclass instanceof ParameterizedType;
Type entityType = ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0];
assert entityType instanceof Class<?>;
return (Class<?>) entityType;
}
};
@SuppressWarnings("unchecked")
protected Class<T> getEntityType() {
return (Class<T>) TYPE_PARAMETER_CACHE.get(this.getClass());
}
public void onMessage(Object message) throws Exception {
onMessage(message, getEntityType()); // getting compile time error here
}
public void onMessage(Object message, Class<T> clazz) throws Exception {
//here my original logic will go
}
}
该 getEntityType
可以在这两个假设失败的子类中重写。
最后,经过几次尝试,我得到了简单而有效的解决方案,但如果可能,我仍然愿意听取其他最佳答案。谢谢
public abstract class AbstractTestLoader<T extends AbstractEntity<T>> {
abstract Class<T> getEntityType();
public void onMessage(TextMessage message) throws Exception {
onMessage(message, getEntityType());
}
public void onMessage(TextMessage message, Class<T> clazz) throws Exception {
//here my original logic will go
}
}
Java通过实现泛型 类型擦除,这意味着它只是一个编译时的概念。程序运行时,a之间没有区别 AbstractTestLoader<Foo>
和a AbstractTestLoader<Bar>
。
有一些解决方法,比如你发现的那个,其中一个类知道它的类型 T
在编译时可以提供实际的类类型。但是没有办法使用纯泛型来发现泛型类型在运行时的含义。