Generic type error: Instance cannot be converted to its own type?

Generic type error: Instance cannot be converted to its own type?

我收到来自以下代码段的编译器错误。错误发生在指示的行:

static abstract class AbstractRoot<R extends Root<R>> implements Root<R> {

    private final Map<Grouping, Phrase> m_ph;

    AbstractSqlRoot() { this.m_ph = new HashMap<>(); }

    @Override public PhraseBuilder<R>    phrase() { 
        PhraseBuilder<R> fr = (PhraseBuilder<R>) m_ph.get(Grouping.PHRASE);
        if (fr == null) {
-->         fr = new PhraseBuilder<R>(this);
            m_ph.put(Grouping.PHRASE, fr);
        }
        return fr; 
    }

HashMap m_ph是一种类型安全的异构容器。类型链接由 Grouping 枚举 class 提供,因此代码中存在的转换是安全的。

PhraseBuilder(及其自己的 AbstractPhraseBuilder)的 class 定义在以下部分中:

public static abstract class AbstractPhrase<R extends Root<R>> implements Phrase {

    private final List<Element>     m_elem;
    private final R                 m_root;

    AbstractPhrase(R r) 
            { m_elem = new ArrayList<>();  m_root = r; }
    :
    :
}


public static final class PhraseBuilder<R extends Root<R>> extends AbstractPhrase<R> {

    public PhraseBuilder()          { this(null);  }
    public PhraseBuilder(R r)       { super(r); }
    :
    :
}

编译器报告 "Incompatible types: AbstractRoot<R> cannot be converted to R where R is a type variable: R extends Root<R> declared in class AbstractRoot."

我很困惑。 AbstractRoot 声明为实现 Root<R>,因此它应该与为 "extends Root<R>" 定义的参数兼容。我没有看到指示的构造函数调用与 class 定义之间的冲突。

有人能帮我解决这个难题吗?我卡住了。


更新:感谢下面给出的答案,我明白了哪里出错了。 SqlRoot<R> 接口的设计确实非常需要将 R 发送到 PhraseBuilder class。已对代码进行如下修补以解决此问题:

static abstract class AbstractRoot<R extends Root<R>> implements Root<R> {

    private final Map<Grouping, Phrase> m_ph;

    AbstractSqlRoot() { this.m_ph = new HashMap<>(); }

    @Override public PhraseBuilder<R>    phrase() { 
        PhraseBuilder<R> fr = (PhraseBuilder<R>) m_ph.get(Grouping.PHRASE);
        if (fr == null) {
-->         fr = new PhraseBuilder<R>(typedThis());
            m_ph.put(Grouping.PHRASE, fr);
        }
        return fr; 
    }
    :
    :
    protected abstract R typedThis();
}

subclass ConcreteRoot 的 class 定义现在包括 typedThis() 的方法声明。这不是一个理想的解决方案,因为该方法成为 class 导出的 API 的一部分,但它解决了问题:

static final class ConcreteRoot extends AbstractRoot<ConcreteRoot> {

    ConcreteRoot() { super(); }

    @Override protected ConcreteRoot typedThis() { return this; }
    :
    :
}

new PhraseBuilder<R>(this) 正在尝试调用此构造函数:

public PhraseBuilder(R r)       { super(r); }

问题是 this 不是 R:它是 AbstractRoot<R>,也恰好是 Root<R>,但它根本不是 R。也许你是这个意思?

fr = new PhraseBuilder<Root<R>>(this);

问题是 thisRoot<R>,不一定是 R。听起来很混乱?这是。这是一个会中断的反例:

public class MyRootA extends AbstractRoot<MyRootA> {
    //R is MyRootA - "this" is an instance of R
}

public class MyRootB extends AbstractRoot<MyRootA> {
   //R is MyRootA - "this" is NOT an instance of R
}

换句话说,没有任何内容表明 Rthis 是同一类型。

像这样自己打字往往适得其反。通常只使用更通用的类型 Root<R> 就足够了。如果你真的想要这个,一个技巧是间接获得对 this 的引用:

 fr = new PhraseBuilder<R>(this.typedThis());

您在 Root<R> 中声明的位置:

 R typedThis();

具体 class 的实现通常只是:

 public MyRootA typedThis() {
    return this;
 }