I have two classes,
public abstract class A {
@Override
public abstract <T extends A> T add();
@Override
public abstract <T extends A> T addWithParam(T param);
}
public class B extends A {
@Override
public B add() {...}
@Override
public B addWithParam(B param) {...}
}
The add() method compiles, but the addWithParam produces an error, saying that addWithParam(B) must override a method in one of the higher classes (A in this scenario). A fix would be to lose the override annotation altogether, but my intentions are to force the user into overriding the method in class B and to return an object of type B.
I could only think of two ways to work around this. The first solution would be to set the return type from the generic type T to A. This would then allow me to return type A, however the user would then have to cast the return result from B.addWithParam(B) into type B, which is what I'm trying to avoid.
The other solution would be to change the visibility of the abstract methods from public to protected (in A.java). Adding onto the previously mentioned solution where I change the return type to A, the inheriting class of A creates a method that returns (B) B.addWithParam(B param) (remember B.addWithParam(B param) returns type A as specified by the super class).
So the question here is, why is the original error produced? Am I just writing the code incorrectly, or does Java directly not support what I'm trying to achieve?
public abstract <T extends A> T add();
What this method declaration means is that for any object a of type A or a subtype, you can call the method a.add() and get back any subtype of A the caller wants. So if you have class B extends A and class C extends A, what you have just told Java is that the following should work:
C c = myB.add();
That's not what you mean. Trust me.
public abstract A add();
would mean that calling add() on any A would at least get you an A back, and that subtypes of A can specify in more detail the exact type they get back, so you could write
class B extends A {
public B add() { ... }
}
That's a bit more reasonable. What this doesn't let you do is specify that the addWithParam method will only accept a B, not another A type.
There is not any way to force a subclass to return instances of its own type. There are various hacks and hints people use to enforce this to varying degrees of effectiveness, such as:
class A<T extends A> {
abstract T add();
abstract T addWithParam(T t);
}
class B extends A<B> {
B add() { ... }
B addWithParam(B b) { ... }
}
and this at least does what you were trying to do. What it won't do is prevent someone from writing class C extends A<B>.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With