2015-01-20 86 views
3

我从下面的代码段收到编译器错误。在所指示的线发生了错误:泛型类型错误:实例无法转换为其自己的类型?

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

回答

2

问题是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 
} 

换句话说,没有什么,指出R相同类型this

这样的自我打字往往适得其反。仅使用更通用的类型Root<R>通常就足够了。如果你真的想这样,一个关键是要获得一个参考this间接:

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

Root<R>声明:

R typedThis(); 

,并在具体的类的实现将通常只:

public MyRootA typedThis() { 
    return this; 
} 
+0

谢谢你。不幸的是,当我为这些东西设计API时,我确实需要在接口'SqlRoot '中返回一个'R'的方法。我看到我出错的地方。从子类获得'R'的解决方案在API上留下可见的瑕疵(这个类不是导出的API的一部分),但它允许我继续前进。谢谢。 – scottb 2015-01-21 13:15:57

4

new PhraseBuilder<R>(this)试图调用此构造:

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

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

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

感谢您的明确,有益的,有用的答案。我现在看到我出错的地方。当我设计这个API时,我真的需要接口'SqlRoot '中的方法来返回一个R.没有重构大量代码就没有办法解决它。出于这个原因'新的PhraseBuilder >(this)'不能帮助我。我真的需要一个'R'。 – scottb 2015-01-21 13:09:55

相关问题