用抽象类方法解决Java泛型类型错误

时间:2017-03-24 04:13:43

标签: java generics abstract-class generic-type-argument

我想在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
    }
}

3 个答案:

答案 0 :(得分:5)

应该注意的是,虽然Java泛型在运行时被擦除,但如果它们存在于类文件中,则检索它们的反射apis有限。

以下是这些假设的快速解决方案:

  1. AbstractTestLoader是直接超类。
  2. 子类在声明超类时不使用类型通配符,例如像class GenericLoader<T extends SubclassAbstractEntity<T>> extends AbstractTestLoader<T>这样的子类不存在。
  3. 以下是代码:

    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

答案 1 :(得分:4)

最后,经过几次尝试,我得到了简单而有效的解决方案,但如果可能,我仍然愿意听取其他最佳答案。感谢

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
    }
}

答案 2 :(得分:2)

Java implements generics via type erasure,这意味着它只是一个编译时的概念。程序运行时,AbstractTestLoader<Foo>AbstractTestLoader<Bar>之间没有区别。

有一些解决方法,比如您发现的解决方法,其中可以使编译时知道T类型的类提供实际的类类型。但是,使用纯泛型无法在运行时发现泛型类型。