typ generyczny - ograniczenie zmiennych typowych

0

Podczas programowania lepiej korzystać z interfejsów niż dziedziczenia.

A jak to wygląda w typach generycznych, gdzie chcemy ograniczyć typ ogólny do jakiegoś interface?
Chcę stworzyć klasę wykorzystująca typ generyczny, ale ten typ powinien mieć dwie metody, niezbędne do prawidłowej pracy.

np

class MojaKlasaGeneryczna<T extends MojInterface>

Pomyślałem sobie, że wszystkie klasy, które będą mogły korzystać z "MojaKlasaGeneryczna" będą musiały impelementować MojInterface, przez co będę miał pewność, że w tych klasach jest wymagana przez "MojaKlasaGeneryczna" metoda.

Czy takie rozwiązanie jest "zgodne ze sztuką" ?
Słowo kluczowe "extends" to tylko zbierzna nazwa z tą, która wykorzystuje się do dziedziczenia? Bo na prawde to w zależności czy jest to klasa - to dziedziczy czy jest interaface to implementuje?

2

Takie rozwiązanie jest jak najbardziej ok. Ale musisz pamięć że typy generyczne nie są kowariantne ani kontrawariantne! To znaczy że MojaKlasaGeneryczna<A> oraz MojaKlasaGeneryczna<B> nie są ze sobą powiązane, nawet jeśli klasy A i B są. Więc zgodnie z klasycznym przykładem, do List<Object> nie możesz przypisać sobie List<String> mimo ze String to Object.

0

Poza tym co napisał @Shalom jest jeszcze zasada PECS – Producer Extends Consumer Super. Opisane tu

0

A jak powinna wyklądać implementacja klasy generycznej z wykorzystaniem Listy jako pola. Mam poniższy kod:

class MojaKlasaGeneryczna <T extends MojInterface>{
        
        private List<T> test;

        public MojaKlasaGeneryczna(List<T> test){
            this.test = test;
        }
    }
List<KlasaNieImplementujacaInterfaceMojInterface> test = new ArrayList<>();

MojaKlasaGeneryczna mojaKlasaGeneryczna = new MojaKlasaGeneryczna(test );

Ale w tym momencie kompilator nie wykrywa, że lista obiektów nie implementuje interface MojInterface

0

Bo teraz to w ogóle zrobiłeś tam jakiś raw-type bo nie przekazałeś żadnego parametru generycznego do MojaKlasaGeneryczna to i co się dziwisz? Ale IDE/Kompilator czasem nie protestują ze masz tu taki nieładny raw-type? Ja widzę:

Unchecked call to 'MojaKlasaGeneryczna(List<T>)' as a member of raw type 'MojaKlasaGeneryczna'

Jakbyś napisał:

MojaKlasaGeneryczna<KlasaNieImplementujacaInterfaceMojInterface> mojaKlasaGeneryczna = new MojaKlasaGeneryczna<>(test);

To nagle byłby błąd:

Type parameter 'KlasaNieImplementujacaInterfaceMojInterface' is not within its bound; should implement 'MojInterface'

Pamiętaj ze java ma wsteczną kompatybilność a java 1.4 nie miała typów generycznych.

0

No tak, masz racje, karygodny bład z mojej strony.
Intellij Community Edition nie protestował.

Czy w takim razie tak mogę zrobić?

public class Test {

    @Test
    public void test(){

        List<KlasaA> listaKlasaA = new ArrayList<>();

        MojaKlasaGeneryczna<KlasaA> klasa = new MojaKlasaGeneryczna<>(listaKlasaA );
    }

    class MojaKlasaGeneryczna <T extends MojInterface>{

        List<T> test = new ArrayList<>();

        public MojaKlasaGeneryczna(List<T> lista){
            this.test.addAll(lista);
        }
    }


    class KlasaA implements MojInterface {

        @Override
        public void get() {

        }
    }

    interface MojInterface {
        void get();
    }
}
0

Bo to nie jest error tylko warning i zaręczam ci że IntelliJ go wyraźnie pokazuje kolorując ten kod inaczej... Tak, tak możesz zrobić.

0

Tak masz racje, pokazuje :) Zafiksowałem się na tym, że nie ma errora i szukłem nie tam gdzie trzeba
Dzięki Shalom.

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