I have a (for me) complex Java generics problem. I read through some documentation and understand some but certainly not all of what I should. Basically, for me, trying to solve it would result in try and error.
In the following, I give a condensed example of my code, once without any generics (so one can hopefully understand what I want to achieve) and the other with some additions that come closer to the solution. Please correct my second version and/or point me to specific documentation. (I have general documentation of Java generics. But my code seems to have several interfering challenges and it is hard to a correct solution)
About my example: There is an abstract base type and several implementing variants (only one is given). Method combine() calls getOp1(), which decides (depending on ) if it should operate on its own instance or on a new one. After the calculation, it returns the target instance.
abstract class Base {
protected final Base getOp1() {
if(Util.isConditionMet()) { return getNewInstance(); }
else { return this; }
}
protected abstract Base getNewInstance(); // returns a new instance of an implementing class
public abstract Base combine(Base other);
}
class Variant extends Base {
public Variant getNewInstance() { return new Variant(); }
public combine(Variant op2) {
Variant op1 = getOp1();
op1.calculate(op2);
return op1;
}
private void calculate(Variant other) { /* some code */ }
}
The version with some generics added. This version is faulty and does not compile.
abstract class Base> {
protected final T getOp1() {
if(Util.isConditionMet()) { return getNewInstance(); }
else { return this; }
}
protected abstract T getNewInstance(); // returns a new instance of an implementing class
public abstract T combine(T other);
}
class Variant> extends Base {
protected T getNewInstance() { return new Variant(); }
public T combine(T op2) {
T op1 = getOp1();
op1.calculate(op2);
return op1;
}
private void calculate(T other) { /* some code */ }
}
解决方案
To make this code working, you need to resolve incompatibility type issues: replace T returning types by Base and cast result of Variant#getOp1() to Variant to allow invoke calculate() on it (this is safe here because Variant#getOp1() always returns Variant:
abstract class Base> {
protected final Base getOp1() {
return condition() ? getNewInstance() : this;
}
protected abstract Base getNewInstance();
public abstract Base combine(T other);
}
class Variant> extends Base {
protected Base getNewInstance() {
return new Variant();
}
public Base combine(T op2) {
Variant op1 = (Variant) getOp1(); //
op1.calculate(op2);
return op1;
}
private void calculate(Base other) {
// ...
}
}
Btw, I still see no reason of such complicated type structure.