Коллекции Java: передать коллекцию детей как коллекцию родителей - PullRequest
7 голосов
/ 03 августа 2010

Скажем, у меня есть интерфейс и некоторые классы:

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

, я получаю, что этот метод не применим дляэто аргументы.Если я попытаюсь перегрузить этот метод как addComponents(Set<LocalizedButton> buttons) в LocalizedButtonsPanel, я, конечно, получу стирание типа.

Может быть, пропущен какой-то шаблон или существует хитрость, чтобы справиться с этой архитектурой для правильного добавленияset 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(); }
}

И в этом случае он работает

Ответы [ 3 ]

6 голосов
/ 03 августа 2010

Измените подпись addComponents () на

public void addComponents(Set<? extends Button> components)

, чтобы методы принимали наборы подклассов Button. Таким образом, вы можете передать Set<LocalizedButton> в качестве аргумента, потому что LocalizedButton расширяет Button и, следовательно, соответствует параметру Type Set<? extends Button>.

5 голосов
/ 03 августа 2010

У вас есть

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

Список создается только для типа кнопки, а не для объекта, расширяющего этот тип.

0 голосов
/ 03 августа 2010

Параметризованные типы не являются ковариантными в Java. Это хорошо, в противном случае вы сможете добавить собаку в список , который был преобразован в список . Вы можете добавить ковариацию на сайте использования, например, List <? extends Animal> может быть назначен List , и вы не можете вызвать его метод add.

...