extends, super, dodawanie liczby do listy, wildcards

0
class NaturalNumber {
 
    private int i;
 
    public NaturalNumber(int i) {
        this.i = i;
    }
    // ...
}
 
class EvenNumber extends NaturalNumber {
 
    public EvenNumber(int i) {
        super(i);
    }
    // ...
}

Wytłumaczy mi ktoś, czemu w poniższych wywołaniach metod generycznych jedne rzeczy działają, a inne nie?
Najbardziej ciekawi mnie przypadek oznaczony w komentarzu przez "ok" (i przeciwny, "błąd")

        List<? extends NaturalNumber> ln = new ArrayList<>();
        ln.add(new NaturalNumber(5)); //błąd
        ln.add(new EvenNumber(5)); //też błąd, ale tutaj mniej dziwi... a powyżej bardziej
 

         
        List<? super EvenNumber> le = new ArrayList<>();
        le.add(new EvenNumber(5)); //ok
        le.add(new NaturalNumber(5)); //błędzik
 
1

"? extends NaturalNumber" może być np EvenNumberem lub jakąś podklasą EvenNumber czy NaturalNumber. Kompilator nie wie jaki tam jest typ, wie tylko że rozszerza NaturalNumber. Dlatego możesz sobie zrobić coś takiego NaturalNumber nn1 = ln.get(0);. Z drugiej strony nie możesz tam nic dodać, bo nie ma określonego z dołu typu.

"? super EvenNumber" może być EvenNumberem, NaturalNumberem lub Objectem. W takim razie na pewno EvenNumber będzie pasował do takiej listy, bo jest podklasą lub tą samą klasą co EvenNumber, NaturalNumber i Object. Podobnie każda podklasa EvenNumber będzie pasować do tej listy.

PS:
Notacji "? extends/super Typ" używa się raczej rzadko, wtedy gdy nie obchodzi nas konkretny typ, np mamy metodę generyczną z listą typu "? extends EvenNumber" jako parametrem i wiemy, że możemy z niej wyciągać instancje EvenNumber (lub podklas) i korzystać z metod tej klasy. Konstrukcję z pytajnikiem trzeba stosować, bo rzutowania typu Typ[A] value = new Typ[B](); nie są dozwolone.

0

Co do tego super - przecież powinno dać się w górę iść. Faktycznie, jak zrobiłem klasę dziedziczącą po EvenNumber, to mogę dodawać jej instancje do listy ? super EvenNumber. Coś takiego raczej powinno być możliwe przy extends, nie super

0

Dobra, chyba skumałem juz. czym innym jest dodawanie obiektow do listy, a czym innym przekazywanie np listy jako parametr.

0

No dokładnie. List<? extends Typ> nie oznacza, że lista może przechowywać podtypy typu Typ, jak i List<? super Typ> nie oznacza, że lista może zawierać nadtypy typu Typ. Lekka niespodzianka, ale to ma sens, tylko trzeba pogłówkować :)

0

@Azarien:
Załóżmy, że mamy taką hierarchię typów: Object -> A -> B -> C

List[B] może zawierać elementy typu B i C.
Do List[? super B] można dodawać elementy tylko typu B lub C, ponieważ dla każdego prawidłowego podstawienia w miejsce pytajnika, element musi pasować do listy. Czyli element musi pasować do List[B], List[A] i List[Object]. Jak nietrudno zauważyć, pasują tylko obiekty typu B lub podklas B.
Do List[? extends B] nie można dodawać żadnych elementów, ponieważ nie da się obliczyć wszystkich prawidłowych podstawień dla pytajnika w czasie kompilacji.

Z List[B] można wyciągnąć elementy i rzutować je na klasę B lub jej nadklasy. Podobnie jest dla listy List[? extends B]. Natomiast z List[? super B] można wyciągnąć tylko Objecty, gdyż tylko Object pasuje dla każdego podstawienia pytajnika.

1 użytkowników online, w tym zalogowanych: 0, gości: 1