Java vs Factory Generators

Setup:

I have an interface for some formats:

interface Formatter<T extends AbstractItem> { String format(T item); } 

I have a factory creating such formats:

 public class Factory { public static Formatter<? extends AbstractItem> create() { switch (something) { case SOMETHING: return new Formatter<SomeItem>() { String format(SomeItem item) {...}}; case SOMETHING_ELSE: return new Formatter<OtherItem>() { String format(OtherItem item){...}}; } 

Now I use this factory to get formatting, and I use it:

 1: Formatter formatter = Factory.create(); 2: for (AbstractItem item : items) { 3: formatter.format(item); 4: } 

The items list contains only the subtexts of AbstractItem that formatter can handle.

Problem:

I get two warnings:

 Line 1: Formatter is a raw type. References to generic type Formatter<T> should be parameterized. Line 3: Type safety: The method format(AbstractItem) belongs to the raw type Formatter. References to generic type Formatter<T> should be parameterized. 

OK, so I'm trying to fix the first one: I know that the factory is returning something from AbstractItem :

 1: Formatter<? extends AbstractItem> formatter = Factory.create(); 

Now the warning on line 1 disappears, but a new error occurs on line 3:

 Line 3: The method format(capture#3-of ? extends AbstractItem) in the type Formatter<capture#3-of ? extends AbstractItem> is not applicable for the arguments (AbstractItem). 

So, if I understand correctly, he complains that AbstractItem not a subtype of AbstractItem (as required by the <? extends AbstractItem> constraint type). Fair enough, but AbstractItem is abstract, so item I go to formatter , always has some type extending AbstractItem ...

How to explain this to the compiler? For now, I decided to go with @SuppressWarnings ...

+7
java generics factory
source share
1 answer

Declaring a method

 public static Formatter<? extends AbstractItem> create() 

You declare that the caller of this method will never know the exact type of Formatter ; the caller will only know that it is Formatter<X> , where X is AbstractItem or its subclass. This way, you cannot pass any instance to the returned Formatter , since you never know which X formatter can handle.

Suppressing a warning here is absolutely wrong, the compiler tells you the right thing: your code is unsafe. Given two subclasses of AbstractItem , Foo and Bar , factory can return a Formatter<Foo> , and you can pass an instance of Bar its format method.

There is a semantic problem that there is no indicator that Formatter your factory will return and why. Or do you make it a concrete factory returning a Formatter<X> , where X is a specific type instead ? extends … ? extends … or you need to add a parameter to give the factory a hint what type of formatting is required, for example

 public static <T extends AbstractItem> Formatter<T> create(Class<T> forItemType) 

Or you turn it into

 public static Formatter<AbstractItem> create() 

indicating that the returned Formatter can handle all types of AbstractItem . Just remember that you can still pass any subclass of AbstractItem to Formatter<AbstractItem> , since each instance of the AbstractItem subclass is still an instance of AbstractItem , just like in pregenerative times.

+6
source share

All Articles