Let's assume two interfaces:
public interface FruitHandler<T extends Fruit>
{
setFruit(T fruit);
T getFruit();
}
public interface Fruit
{
}
Now I want a factory to create FruitHandlers
(e.g. AppleHander
, OrangeHandler
, ...), but the FruitHandlerFactory
does not know neccessary about the implementing classes of both interfaces (like in java parameterized generic static factory). The FruitHandlerFactory
should work in this way (where OrangeHandler
implements FruitHandler
and Orange
implements Fruit
):
FruitHandlerFactory fhf = new FruitHandlerFactory<OrangeHandler,Orange>();
OrangeHandler fh = fhf.create();
Orange orange = (Orange)fh.getFruit();
This should be the factory:
public class FruitHandlerFactory<A extends FruitHandler, B extends Fruit>
{
public FruitHandler create()
{
FruitHandler<Fruit> fh = new A<B>(); //<--- ERROR
fh.setFruit(new B());
return fh;
}
}
Where I get this error:
The type A is not generic; it cannot be parameterized with arguments <B>
BTW: Is it possible to make the create()
method static?
Since generics in Java are implemented using erasure, the type information of FruitHandlerFactory
will not be available at runtime, which means you can't instantiate A
(or B
) this way.
You can, however pass in a Class
object of the correct type to work around this:
public class FruitHandlerFactory<H extends FruitHandler<F>, F extends Fruit> { final Class<H> handlerClass; final Class<F> fruitClass; public FruitHandlerFactory(final Class<H> handlerClass, final Class<F> fruitClass) { this.handlerClass = handlerClass; this.fruitClass = fruitClass; } public H create() throws InstantiationException, IllegalAccessException { H handler = handlerClass.newInstance(); handler.setFruit(fruitClass.newInstance()); return handler; } }
A minor drawback is that you'll have to write the type names three times(1) if you want to instantiate a FruitHandlerFactory
:
FruitHandlerFactory fhf = new FruitHandlerFactory<OrangeHandler,Orange>(OrangeHandler.class, Orange.class);
You can somewhat reduce that by producing a static
createFactory()
method on your FruitHandlerFactory
:
static <H extends FruitHandler<F>, F extends Fruit> FruitHandlerFactory<H, F> createFactory( final Class<H> handlerClass, final Class<F> fruitClass) { return new FruitHandlerFactory<H, F>(handlerClass, fruitClass); }
and use it like this:
FruitHandlerFactory fhf = FruitHandlerFactory.createFactory(OrangeHandler.class, Orange.class);
From this question:
Perhaps try this?
public class FruitHandlerFactory<A extends FruitHandler<B>, B extends Fruit>
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