Java Collections: Pass collection of children as collection of parents
Say I have an interface and some classes:
public interface IPanel<ComponentType extends Component> {
public void addComponents(Set<ComponentType> components);
public ComponentType create();
}
public class Button extends Component { }
public class LocalizedButton extends Button { }
public class ButtonsPanel implements IPanel<Button> {
public void addComponents(Set<Button> components) { ... /* uses create() */ ; }
public Button create() { return new Button(); }
}
public class LocalizedButtonsPanel extends ButtonsPanel {
public Button create() { return new LocalizedButton(); }
}
Then I have a set of LocalizedButtons and when I call
final LocalizedButtonsPanel localizedButtonsPanel = new LocalizedButtonsPanel();
final Set<LocalizedButton> localizedButtonsSet = new LinkedHashSet<LocalizedButton>();
localizedButtonsPanel.addComponents(localizedButtonsSet);
I get that this method is not applicable for this arguments.
If I try to overload this method as addComponents(Set<LocalizedButton> buttons)
in LocalizedButtonsPanel
, I get type erasure, of course.
May be some pattern is missed or the trick exists to deal with this architecture to implement correct adding the set of LocalizedButtons?
I've got the answer and I want to make my example more concrete - I have some validators in my implementation, so I need the collection type to be als开发者_如何学编程o stored as generic, that is simplified code I've got using the answer:
public interface IPanel<ComponentType extends Component, CollectionType extends Collection<? extends Component>> extends Validated<CollectionType> {
public void addComponents(CollectionType components);
public ComponentType create();
}
public class Button extends Component { }
public class LocalizedButton extends Button { }
public class ButtonsPanel implements IPanel<Button, Set<? extends Button>> {
public void addComponents(Set<? extends Button> components) { ... /* uses create() */ ; }
public Button create() { return new Button(); }
}
public class LocalizedButtonsPanel extends ButtonsPanel {
public Button create() { return new LocalizedButton(); }
}
And in this case, it works
Change the addComponents() signature to
public void addComponents(Set<? extends Button> components)
so that the methods accepts sets of subclasses of Button.
This way, you can pass a Set<LocalizedButton>
as an argument, because LocalizedButton
extends Button
and therefore matches the parameter Type of Set<? extends Button>
.
You have
public class ButtonsPanel implements IPanel<Button> {
public void addComponents(Set<Button> components) { ... /* uses create() */ ; }
public Button create() { return new Button(); }
}
Should be
public class ButtonsPanel implements IPanel<Button> {
public void addComponents(Set<? extends Button> components) { ... /* uses create() */ ; }
public Button create() { return new Button(); }
}
The list is created only for the type of button not for Object that extend that type.
Parameterised types are not covariant in Java. This is good, otherwise you would be able to add a Dog to a List<Cat> that had been upcast to List<Animal>. You can add covariance at the usage site, e.g., List<? extends Animal> can be assigned a List<Cat> and you can't call its add method.
精彩评论