I'm new to using bounded types in Java, and I'm not sure if the following is a programming error because of a bad use of inheritance or a javac
bug
I need to define two different type of objects: things which have to be managed and managers of that things. That's why I created an abstract class to model the common behavior of those things
public abstract class AbstractThing {
// Common method implemented
public void hello() {
System.out.println("HI, I'm AbstractThing");
}
}
and an interface to define the methods that those things' manager must implement
public interface AbstractManager {
// Operation that a things' manager must implement
public <T extends AbstractThing> void greet(T t);
}
So suppose I create two concrete things classes, one of them just inherits the abstract one:
public class Thing extends AbstractThing {
// Constructor
public Thing() {}
}
but the other one implements an own method:
public class AnotherThing extends AbstractThing {
// Constructor
public AnotherThing() {}
// Extra method which this class implements
public void goodbye() {
System.out.println("BYE, I'm AnotherThing");
}
}
But when I define a manager as follows:
public class Manager implements AbstractManager {
// Constructor method
public Manager() {}
// Implementation of the interface's method fails
@Override
public <AnotherThing extends AbstractThing>
void greet(AnotherThing t) {
// I can use this method, which AnotherThing inherits from AbstractThing
t.hello();
// But I can't use this one defined by AnotherThing
t.goodbye();
}
}
I get the error:
AnotherManager.java:15: error: cannot find symbol
t.goodbye();
^
symbol: method goodbye()
location: variable t of type AnotherThing
where AnotherThing is a type-variable:
AnotherThing extends AbstractThing declared in method <AnotherThing>greet(AnotherThing)
1 error
And I don't understand why, because it's recognizing the class as AnotherThing
, but it's dealing it as AbstractThing
. I've tried to cast the object as the subclass, but it doesn't work
I've also checked that it only happens when I try to access the subtype methods, because the following manager compile and works perfectly:
public class Manager implements AbstractManager {
// Constructor method
public Manager() {}
// Implementation of the method defined into the interface
@Override
public <Thing extends AbstractThing>
void greet(Thing t) {
t.hello();
}
// I can overload the method "greet" without overriding the interface
// and it works for AnotherThing
public void greet(AnotherThing t) {
t.hello();
t.goodbye();
}
}
Any idea about what's happening there?
Here's why
It's not difficult to figure out if you do something like this
public class Manager implements AbstractManager {
// Constructor method
public Manager() {}
// Implementation of the interface's method fails
@Override
public <T extends AbstractThing>
void greet(T t) {
// I can use this method, which T inherits from AbstractThing
t.hello();
// But I can't use this one because T inherits from AbstractThing which does not know this method
t.goodbye();
}
}
In other words, the word before the "extends" is not supposed to be a class name, but a generic identifier (a variable name).
In this case, since T (or wharever you call it) is AbstractThing, it does not know what goodbye() is.
Now, why your last example works?
Because you're saying that greet receives a object of type AnotherThing, not a generic type such as T.