/ / Hierarchie i generyczne - java, generyczne

Hierarchie i generics - java, generics

W mojej aplikacji mam model oparty głównie na dwóch hierarchiach klas: kontenerach i elementach. Kontenery mają odniesienia do elementów za pośrednictwem list.
Rozważmy na przykład klasę Java Child to jest podtyp Parent i ElementChild to jest podtyp ElementParent. Elementy są używane jako parametry typulist i chciałbym, aby każdy kontener mógł dodawać, usuwać i pobierać elementy ze swojej listy. Lista ta powinna być jak najbardziej restrykcyjna, tzn. Powinna zawierać elementy umieszczone na tym samym poziomie hierarchii (Child - ElementChild).

wiem to List<ElementParent> i List<ElementChild> nie są w relacji podtypu, czy istnieje lepsze podejście niż tylko utworzenie dwóch różnych list (List<ElementParent> w Parent i List<ElementChild> w Child)?

W poniższym przykładzie użyłem odziedziczonej listy, aby pokazać, co mam na myśli, ale oczywiście nie kompiluje się:

public class Parent {

protected List<ElementParent> list;

public Parent () {
list = new ArrayList<ElementParent>();
}

public List<ElementParent> getList() {
return list;
}

public void add(ElementParent element) {
list.add(element);
}

public void remove (ElementParent element) {
list.remove(element);
}

public void setList(List<ElementParent> list) {
this.list = list;
}
}

public class Child extends Parent {


public Child() {
list = new ArrayList<ElementChild>(); // does not compile
}

public List<ElementChild> getList() { //does not compile
return list;
}

public void add(ElementChild element) {
list.add(element);
}

public void remove (ElementChild element) {
list.remove(element);
}

public void setList(List<ElementChild> list) { //does not compile
this.list = list;
}

}

Odpowiedzi:

1 dla odpowiedzi № 1

Twoje pytanie pokazuje, dlaczego List<ElementParent> i List<ElementChild> nie są w relacji podtypu.

Od Child extends Parent i Parent::add(ElementParent element) metoda istnieje, dlatego jest dziedziczona do Child.

Teraz możesz napisać:

ElementParent ep = ...;
Child child = ...;
child.add(ep); //perfectly legal

Ale co by to zrobiło? Dodaj ElementParent do listy ElementChilds I to jest powód dlaczego List<ElementParent> i List<ElementChild> nie są w relacji podtypu.

Jak więc rozwiązać problem?

Na przykład mogą tu pomóc symbole wieloznaczne List<ElementParent> i List<ElementChild> oba są List<? extends ElementParent> i umiesz czytać ElementParent od List<? extends ElementParent>, ale niestety nie można do tego niczego napisać (oprócz null).

Podobnie z dolną granicą List<? super ElementChild>, ale na twoim miejscu ponownie zastanowiłbym się, co dokładnie chcesz osiągnąć i czy można zastosować inne podejście.


2 dla odpowiedzi nr 2

Jest to drażliwy problem znany jako podtyp kowariantny. Krótko mówiąc, oznacza to, że kiedy jesteśrozszerzając (np. podklasę) klasę i nadpisując niektóre z jej metod, nie można zmienić typu parametrów tych metod. Jeśli to dozwolone, kompilator nie będzie w stanie zapewnić gwarancji bezpieczeństwa Java.

AFAIK jedynym rozwiązaniem Twojego problemu jest poleganie w większym stopniu na lekach generycznych. W szczególności musisz zdefiniować klasę, która jest sparametryzowana zarówno dla typu elementu, jak i typu listy:

public class Base<E, L extends List<E>> {

protected L list;

public Base(L l) { list = l; }

public L getList() { return list; }
public void add(E element) { list.add(element); }
public void remove(E element) { list.remove(element); }
public void setList(L list) { this.list = list; }
}

Następnie możesz zdefiniować Parent i Child jako podklasy Base, przekazując rzeczywiste typy dla E i L parametry typu:

public class Parent extends Base<ElementParent,List<ElementParent>> {
public Parent() {
super(new ArrayList<ElementParent>());
}
}

public class Child extends Base<ElementChild, List<ElementChild>> {
public Child() {
super(new ArrayList<ElementChild>());
}
}