我從下面的代碼段收到編譯器錯誤。在所指示的線發生了錯誤:泛型類型錯誤:實例無法轉換爲其自己的類型?
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
enum類提供,因此代碼中的轉換是安全的。
類定義爲PhraseBuilder(和它自己的AbstractPhraseBuilder)按照在下面的部分:
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); }
:
:
}
編譯器報告「不兼容的類型:AbstractRoot<R>
不能轉換到R,其中R是一種類型的變量:R extends Root<R>
在課堂上申報AbstractRoot
「。
我很困惑。 AbstractRoot
被宣佈執行Root<R>
,因此它應該與爲「擴展Root<R>
」定義的參數兼容。我沒有看到指定的構造函數調用和類定義之間的衝突。
任何能幫助我解決這個難題的人?我卡住了。
UPDATE:由於下面給出的答案,我得到我哪裏錯了。 SqlRoot<R>
接口的設計確實需要將R
發送到PhraseBuilder
類。代碼已修補如下來解決這個問題:
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();
}
類定義爲子類ConcreteRoot
現在包括用於typedThis()
方法聲明。事實上,自該方法的理想的解決方案將成爲類的出口API的一部分,但它解決了這個問題:
static final class ConcreteRoot extends AbstractRoot<ConcreteRoot> {
ConcreteRoot() { super(); }
@Override protected ConcreteRoot typedThis() { return this; }
:
:
}
謝謝你。不幸的是,當我爲這些東西設計API時,我確實需要在接口'SqlRoot'中返回一個'R'的方法。我看到我出錯的地方。從子類獲得'R'的解決方案在API上留下可見的瑕疵(這個類不是導出的API的一部分),但它允許我繼續前進。謝謝。 –
scottb
2015-01-21 13:15:57