调用通用接口方法不起作用 [英] Calling a Generic Interface Method does not work

查看:119
本文介绍了调用通用接口方法不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个通用接口,其中一个方法接受泛型类型的参数:

  public interface ComponentRenderer< T extends GuiComponent> ; {
public void draw(T component);





$ b

另外我有一个抽象类,它声明了这个接口类型的一个变量,它使用一个有界的通配符:

  public abstract class GuiComponent extends Gui {
private ComponentRenderer<扩展Gui组件> componentRenderer;

public void draw(){
this.componentRenderer.draw(this);
}

//以及ComponentRenderer的setter和getter
}

和一个子类,为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){
// ...
}
}

我看不到我错了什么,但是调用 componentRenderer.draw(this)在GuiComponent中不起作用,出现以下错误:



据我了解,它说我不能使用GuiComponent,因为它不是从GuiComponent派生的,没有任何意义。我也试过? super GuiComponent ,它将接受 draw()调用,但不接受 FlatButtonRenderer $ b

我不明白这个语法错误,有没有人有一个想法,我需要如何更改代码?

编辑:
当我在draw()的调用中使用我的IDE代码完成时,它说我接受一个类型为null的参数,所以出于某种原因,它不是能够弄清楚,至少要输入参数......

问题是,?扩展GuiComponent 的意思是 GuiComponent 的一个特定子类型,但不知道哪个。

编译器不知道这个对于 ComponentRenderer 是正确的 GuiComponent 子类型。 code>。这可能是渲染器只能与其他特定的子类一起工作。



您必须使用某种自我类型模式以类型安全的方式执行此操作。这样你就可以将渲染器的类型变量与 GuiComponent 子类的类型连接。



例子:

  class Gui {} 
$ b $ interface ComponentRenderer< T extends GuiComponent< T>> {
public void draw(T component);
}

// T是自我类型。子类将它设置为它们自己的类型。这样这个类
//可以引用它的子类的类型。
抽象类GuiComponent< T extends GuiComponent< T>>扩展Gui {
private ComponentRenderer< T> componentRenderer;

public void draw(){
this.componentRenderer.draw(thisSub());


public void setComponentRenderer(ComponentRenderer< T> r){}

//超类需要使用此方法才能使用'this'
//带有子类型。子类必须覆盖它才能返回'this'
public abstract T thisSub();

//以及ComponentRenderer的setter和getter
}

//这里设置自我类型参数
class GuiButton extends GuiComponent< GuiButton> {
public GuiButton(/ * ... * /){
// ...
this.setComponentRenderer(new FlatButtonRenderer());
}

class FlatButtonRenderer实现ComponentRenderer< GuiButton> {
@Override
public void draw(final GuiButton component){
// ...
}
}

@Override
public GuiButton thisSub(){
return this;






$ b

原本(我认为)称为好奇地重现模板模式这个答案更多地解释了它。


I got a generic interface with one method accepting a parameter of the generic type:

public interface ComponentRenderer<T extends GuiComponent> {
    public void draw(T component);
}

Furthermore I have an abstract class, that declares a variable of this interface type using a bounded wildcard:

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
}

And a subclass, wich set a implementation for the componentRenderer:

public class GuiButton extends GuiComponent {
    public GuiButton(/* ... */) {
        //...
        this.setComponentRenderer(new FlatButtonRenderer());
    }

where FlatButtonRenderer is implemented as:

public class FlatButtonRenderer implements ComponentRenderer<GuiButton> {

    @Override
    public void draw(final GuiButton component) {
        //...
    }
}

I can't see where I got something wrong, but the call componentRenderer.draw(this) in GuiComponent does not work with the following error:

As far as I understand this, it says me, that I can't use GuiComponent because it does not derive from GuiComponent, what makes no sense. I've also tried ? super GuiComponent, which will accept the draw() call, but then does not accept the implementation of FlatButtonRenderer

I do not understand this syntax error, does anyone have an idea, how I need to change the code?

EDIT: When I use my IDE's code completion on the call of draw(), it says me, that draw accept one argument of type "null", so for some reason, it is not able to figure out, wich type the argument should be...

解决方案

The problem is that ? extends GuiComponent means "one specific subtype of GuiComponent, but unknown which".

The compiler does not know that this is of the right GuiComponent subtype for the ComponentRenderer. It could be that the renderer only can work with some other specific subclass.

You have to use some kind of self-type pattern to do this in a type-safe way. That way you kind of "connect" the type variable of the renderer with the type of the GuiComponent subclass.

Example:

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

This is originally (I think) called the curiously recurring template pattern. This answer explains it more.

这篇关于调用通用接口方法不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆