【问题标题】:Incompatible classes of java genericsjava泛型的不兼容类
【发布时间】:2016-04-26 15:17:44
【问题描述】:

看来我又被 java 泛型困住了。这是我所拥有的:

几个类:

class CoolIndex implements EntityIndex<CoolEntity>

class CoolEntity extends BaseEntity

使用上面的类枚举:

enum Entities {
    COOL_ENTITY {
        @Override
        public <E extends BaseEntity, I extends EntityIndex<E>> Class<I> getIndexCls() {
            return CoolIndex.class;
        }

        @Override
        public <E extends BaseEntity> Class<E> getEntityCls() {
            return CoolEntity.class;
        }
    }

    public abstract <E extends BaseEntity, I extends EntityIndex<E>> Class<I> getIndexCls();

    public abstract <E extends BaseEntity> Class<E> getEntityCls();    
}

我需要使用getIndexCls()函数调用的结果来调用函数:

static <E extends BaseEntity, I extends EntityIndex<E>> boolean isSomeIndexViewable(Class<I> cls)

问题是编译器抱怨return CoolIndex.class;return CoolEntity.class;,我不清楚为什么...当然我可以将它转换为Class&lt;I&gt;(第一种情况),但在我看来我是试图掩盖我的误解,感觉不对。

【问题讨论】:

标签: java generics types


【解决方案1】:

getIndexCls 的问题在于,因为它是泛型的,所以类型参数可以解释为任何符合声明边界的类。你可能认为CoolIndex.class 符合这些界限,确实如此,但是该方法的调用者可以提供他们自己的不兼容的类型参数,例如:

Entities.COOL_ENTITY.<UncoolEntity, UncoolIndex>getIndexCls();

这会破坏类型安全,因此编译器不允许这样做。您可以强制转换为Class&lt;I&gt;,但出于同样的原因,编译器会警告您有关未经检查的强制转换。它会编译,但正如我所描述的那样,它可能会导致运行时问题。

其他情况可以通过传递Class&lt;I&gt; 对象以使类型推断正常工作来解决这种情况,但这违背了此方法的要点——返回Class&lt;I&gt; 对象。

其他情况需要将泛型类型参数从方法移动到类,但您使用的是不能泛型的枚举。

我想出的获得类似于 compile 的唯一方法是完全删除 enum。使用抽象类,以便您可以声明类级别的类型参数。使用您想要的类型参数实例化常量。

abstract class Entities<E extends BaseEntity, I extends EntityIndex<E>> {
    public static final Entities<CoolEntity, CoolIndex> COOL_ENTITY = new Entities<CoolEntity, CoolIndex>() {
        @Override
        public Class<CoolIndex> getIndexCls() {
            return  CoolIndex.class;
        }

        @Override
        public Class<CoolEntity> getEntityCls() {
            return CoolEntity.class;
        }
    };

    // Don't instantiate outside this class!
    private Entities() {}

    public abstract Class<I> getIndexCls();
    public abstract Class<E> getEntityCls();
}

【讨论】:

  • 感谢您的解决方案。无论如何,它看起来有点脏,但我想这是这种情况下最“正确”的解决方案。
【解决方案2】:

这可以通过更简单的例子来重现:

public <E extends BaseEntity> E get() {
    return new BaseEntity(); // compilation error here
}

这种声明&lt;E extends BaseEntity&gt; 中的问题是您的方法声称返回调用者应该询问的任何类型E 的实例:

MyCoolEntity1 e = get(); // valid, E is MyCoolEntity1
MyCoolEntity2 e = get(); // valid, E is MyCoolEntity2

这段代码应该是编译时安全的,所以你必须将你的方法的结果转换为E

public <E extends BaseEntity> E get() {
    return (E) new BaseEntity(); // no error, but unsafe warning
}

在您的示例中几乎相同,您声称返回 Class&lt;E&gt; 类型的值:

public <E extends BaseEntity> Class<E> getEntityCls() 

但返回一个具体的类SomeEntity.class,即Class&lt;CoolEntity&gt;


好的,我应该如何解决这个问题?
  1. 您可以添加类型转换return (Class&lt;I&gt;) CoolIndex.class; / return (Class&lt;E&gt;) CoolEntity.class;

  2. 您可以将枚举替换为类,因为枚举不能是泛型的,而类可以

  3. 您可以完全删除泛型,因为它没有太多价值

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-11
    • 2018-08-16
    • 2011-04-18
    • 2015-07-03
    相关资源
    最近更新 更多