Java generics with inheritance and

I have (for me) a difficult issue with Java generics. I read some documents and understood some, but, of course, not everything I need. Basically, for me, trying to solve this will lead to an attempt and an error.

Next, I give a concise example of my code once without any generics (so you can hope to understand what I want to achieve), and the other with some additions that come close to the solution. Please correct my second version and / or provide me with specific documentation. (I have general documentation on Java generics. But my code seems to have a few hurdles, and this is difficult for a proper solution)

In my example: there is an abstract base type and several implementation options (only one is provided). The combine() method calls getOp1() , which solves (depending on <some condition> ) if it should work on its own instance or on a new one. After calculation, the target instance is returned.

 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 */ } } 

Added version with some generics. This version is malfunctioning and does not compile.

 abstract class Base<T extends Base<T>> { 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<T extends Variant<T>> extends Base<T> { 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 */ } } 
0
source share
2 answers

For this code to work, you need to solve incompatibility issues: replace the T return types with Base<T> and produce the result from Variant#getOp1() to Variant<T> to allow it to use calculate() (this is safe here, since Variant#getOp1() always returns Variant :

 abstract class Base<T extends Base<T>> { protected final Base<T> getOp1() { return condition() ? getNewInstance() : this; } protected abstract Base<T> getNewInstance(); public abstract Base<T> combine(T other); } class Variant<T extends Variant<T>> extends Base<T> { protected Base<T> getNewInstance() { return new Variant(); } public Base<T> combine(T op2) { Variant<T> op1 = (Variant<T>) getOp1(); // <- explicit cast op1.calculate(op2); return op1; } private void calculate(Base<T> other) { // ... } } 

Btw, I still do not see the reasons for such a complex type structure.

0
source

I saw a couple of such combinational, operational classes, although not too complicated. Inheritance may not be the right tool.

It is better to use the search engine for features and functions.

 class Base { // Untyped private Map<Class<?>, Object> capabilities = new HashMap<>(); protected <I> void register(Class<I> intf, I obj) { capabilities.put(intf, obj); } public <T> Optional<T> lookup(Class<T> intf) { Object obj = capabilities.get(intf); return obj == null ? Optional.emtpy() : Optional.of(intf.cast(obj)); } } interface Flying { void fly(double altitude); } Base pelican = new Pelican(); Flying flying = pelical.lookup(Flying.class).orElse(null); flying.fly(0.5); 

It also allows dynamic changes and combine things in two ways.

0
source

All Articles