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);
问题是 this
是 Root<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
}
换句话说,没有任何内容表明 R
与 this
是同一类型。
像这样自己打字往往适得其反。通常只使用更通用的类型 Root<R>
就足够了。如果你真的想要这个,一个技巧是间接获得对 this
的引用:
fr = new PhraseBuilder<R>(this.typedThis());
您在 Root<R>
中声明的位置:
R typedThis();
具体 class 的实现通常只是:
public MyRootA typedThis() {
return this;
}
我收到来自以下代码段的编译器错误。错误发生在指示的行:
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);
问题是 this
是 Root<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
}
换句话说,没有任何内容表明 R
与 this
是同一类型。
像这样自己打字往往适得其反。通常只使用更通用的类型 Root<R>
就足够了。如果你真的想要这个,一个技巧是间接获得对 this
的引用:
fr = new PhraseBuilder<R>(this.typedThis());
您在 Root<R>
中声明的位置:
R typedThis();
具体 class 的实现通常只是:
public MyRootA typedThis() {
return this;
}