我得到了一个通用接口,其中有一个接受通用类型参数的方法:
public interface ComponentRenderer<T extends GuiComponent> {
public void draw(T component);
}
此外,我还有一个抽象类,该类使用有界通配符声明此接口类型的变量:
public abstract class GuiComponent extends Gui {
private ComponentRenderer<? extends GuiComponent> componentRenderer;
public void draw() {
this.componentRenderer.draw(this);
}
//and a setter and getter for the ComponentRenderer
}
还有一个子类,它为componentRenderer设置了一个实现:
public class GuiButton extends GuiComponent {
public GuiButton(/* ... */) {
//...
this.setComponentRenderer(new FlatButtonRenderer());
}
FlatButtonRenderer实现为:
public class FlatButtonRenderer implements ComponentRenderer<GuiButton> {
@Override
public void draw(final GuiButton component) {
//...
}
}
我看不到哪里出错了,但是GuiComponent中的
componentRenderer.draw(this)
调用不适用于以下错误:据我了解,它告诉我,我不能使用GuiComponent,因为它不是从GuiComponent派生的,这没有任何意义。我也尝试过
? super GuiComponent
,它将接受draw()
调用,但是不接受FlatButtonRenderer
的实现。我不理解此语法错误,是否有人知道我该如何更改代码?
编辑:
当我在调用draw()时使用我的IDE的代码完成时,它说我说draw接受一个类型为“ null”的参数,因此由于某种原因,它无法弄清楚该参数应为哪种类型。 ..
最佳答案
问题在于? extends GuiComponent
的意思是“ GuiComponent
的一个特定子类型,但不知道哪个”。
编译器不知道this
是GuiComponent
的正确ComponentRenderer
子类型。可能是渲染器只能与其他某些特定子类一起使用。
您必须使用某种自类型模式来以类型安全的方式执行此操作。这样,您就可以将渲染器的类型变量与GuiComponent
子类的类型“连接”在一起。
例:
class Gui {}
interface ComponentRenderer<T extends GuiComponent<T>> {
public void draw(T component);
}
// T is the self-type. Subclasses will set it to their own type. In this way this class
// can refer to the type of its subclasses.
abstract class GuiComponent<T extends GuiComponent<T>> extends Gui {
private ComponentRenderer<T> componentRenderer;
public void draw() {
this.componentRenderer.draw(thisSub());
}
public void setComponentRenderer(ComponentRenderer<T> r) {}
// This method is needed for the superclass to be able to use 'this'
// with a subclass type. Sub-classes must override it to return 'this'
public abstract T thisSub();
//and a setter and getter for the ComponentRenderer
}
// Here the self-type parameter is set
class GuiButton extends GuiComponent<GuiButton> {
public GuiButton(/* ... */) {
//...
this.setComponentRenderer(new FlatButtonRenderer());
}
class FlatButtonRenderer implements ComponentRenderer<GuiButton> {
@Override
public void draw(final GuiButton component) {
//...
}
}
@Override
public GuiButton thisSub() {
return this;
}
}
我最初将其称为curiously recurring template pattern。 This answer进一步说明。