Java集合框架:将子类型的集合作为父类型的集合传递

7

假设我有一个接口和一些类:

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(); }
}

然后我有一组LocalizedButtons,当我调用它们时:
final LocalizedButtonsPanel localizedButtonsPanel = new LocalizedButtonsPanel();
final Set<LocalizedButton> localizedButtonsSet = new LinkedHashSet<LocalizedButton>();
localizedButtonsPanel.addComponents(localizedButtonsSet);

我明白这种方法不适用于这些参数。 如果我尝试在LocalizedButtonsPanel中重载此方法为addComponents(Set<LocalizedButton> buttons),当然会得到类型擦除。
也许有一些模式被忽略了或者存在处理这种架构以正确添加LocalizedButtons集合的技巧?
我已经得到了答案,并且想使我的示例更具体化-我在我的实现中有一些验证器,因此我需要将集合类型存储为泛型,这是使用答案简化的代码:
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(); }
}

在这种情况下,它是可行的。

可能有一个类似的问题https://dev59.com/L0XRa4cB1Zd3GeqPus2D,但那里的答案会破坏我所拥有的接口。 - shaman.sir
3个回答

7
将 addComponents() 方法签名更改为:
public void addComponents(Set<? extends Button> components)

这样,方法就可以接受一组Button的子类。这样,您可以将Set<LocalizedButton>作为参数传递,因为LocalizedButton扩展了Button,因此与Set<? extends Button>的参数类型匹配。


哦,是的,谢谢。我的结构有点更复杂(我会在问题中描述),但我已经根据您的建议纠正了我的泛型,它确实很合适 :)。 - shaman.sir

5

你有

public class ButtonsPanel implements IPanel<Button> {
    public void addComponents(Set<Button> components) { ... /* uses create() */ ; }
    public Button create() { return new Button(); }
}

应该是

public class ButtonsPanel implements IPanel<Button> {
    public void addComponents(Set<? extends Button> components) { ... /* uses create() */ ; }
    public Button create() { return new Button(); }
}

该列表仅针对按钮类型,而不是扩展该类型的对象。


1
这个代码 public class ButtonsPanel implements IPanel<? extends Button> 不会起作用,因为在 implements 部分不支持通配符。如果我指定以下代码:public class GenericButtonsPanel<ButtonType extends Button> implements IPanel<ButtonType>那么在这种情况下,LocalizedButtonsPanel extends GenericButtonsPanel<LocalizedButton> 将不是 ButtonsPanel 的子类,而 ButtonsPanelextends GenericButtonsPanel<Button> 的。我需要没有泛型的构造函数。 - shaman.sir

0

Java中的参数化类型不是协变的。这是好的,否则你将能够将Dog添加到已向上转型为List<Animal>的List<Cat>中。您可以在使用位置处添加协变性,例如,List<? extends Animal>可以分配给List<Cat>,并且无法调用其add方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接