Reputation: 581
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...
Upvotes: 2
Views: 1300
Reputation: 12131
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.
Upvotes: 2
Reputation: 147
In GuiComponent, change your declaration of componentRenderer to this:
ComponentRenderer<GuiComponent> componentRenderer;
Upvotes: 0