Reputation: 32054
I have a class ShapeDescriber
that looks like this:
public class ShapeDescriber<T extends Shape> {
public void describe(T shape) {
System.out.println("Its color is " + shape.getColor());
}
}
I use T
so that subclasses can do something like:
public class CircleDescriber<T extends Circle> extends ShapeDescriber<T> {
public void describe(T circle) {
super.describe(circle);
System.out.println("Its radius is " + circle.getRadius());
}
}
Ultimately, I want this Describer
type hierarchy to match the type hierarchy of my model.
The problem that I run into, is that inside the CircleDescriber
, I can't pass a Circle
to my describe()
method! When I try this:
public class CircleDescriber ... {
...
public void printATest() {
Circle c = new Circle(Colors.GREEN, 10);
this.describe(c);
}
}
There's a compilation error on my describe()
call, because:
The method describe(T) in the type CircleDescriber<T> is not applicable for the arguments (Circle)
Wait. What? I feel like this class knows that every instance of a T
will be a subclass of Circle
, no?
Edit: I have created a Gist here for easy copypasting: https://gist.github.com/craigotis/135f88b1ce8beca07400
Note the above Gist will fail to compile.
Upvotes: 0
Views: 912
Reputation: 12205
I think this should work as is, but depending a bit on how you instantiate the CircleDescriber
. This should work:
new CircleDescriber<Circle>().describe(circle);
The reason that this does not compile is that you have the test method inside the CircleDescriber
, with a call to this
. Since the compiler does not know the generic parameter of this
, it can't say for sure that passing a Circle
to it will work (what if this
refers to a CircleDescriber
parameterized to a subclass of Circle
?) Change this
with new CircleDescriber<Circle>()
in your test-method, and it shold compile.
But, here you see that you are actually specifying that you are describing a Circle
twice, both in the class name and in the generic parameter. This should not be necessary, at least as long as Circle
is a leaf node in your hierarchy. Instead, do this:
(Keep ShapeDescriber
as is)
public class CircleDescriber extends ShapeDescriber<Circle> {
@Override
public void describe(Circle circle) {
super.describe(circle);
System.out.println("Its radius is " + circle.getRadius());
}
}
Upvotes: 3
Reputation: 19284
Declaring :
public class CircleDescriber<T extends Circle> extends ShapeDescriber<T>
Means that
CircleDescriber.describe()
gets some class extending Circle
. For example:
Having a class: public class RedCircle extends Circle
, you can declare:
CircleDescriber describer = CircleDescriber<RedCircle>
meaning that describer
can get RedCircle
only (and not Circle
). That's why it is not allowed.
Changing to:
public class CircleDescriber extends ShapeDescriber<Circle>
Would work if you can use Circle
only.
Upvotes: 1