Dzisiaj przeczytałem kilka artykułów na temat kowariancji, kontrawariancji (i niezmienności) w Javie. Przeczytałem artykuł w angielskiej i niemieckiej Wikipedii oraz kilka innych postów na blogu i artykułów z IBM.
Ale nadal jestem trochę zdezorientowany, o co dokładnie chodzi? Niektórzy mówią, że chodzi o relacje między typami i podtypami, niektórzy mówią, że chodzi o konwersję typów, a niektórzy twierdzą, że jest to używane do decydowania, czy metoda jest nadpisywana, czy przeciążana.
Szukam więc prostego wyjaśnienia w prostym języku angielskim, które pokaże początkującemu, czym jest kowariancja i kontrawariancja (oraz niezmienność). Plus za łatwy przykład.
Odpowiedzi:
Wszystkie powyższe.
W istocie te terminy opisują, jak na relację podtypów wpływają transformacje typów. Oznacza to, że jeśli
A
iB
są typami,f
jest transformacją typu i ≤ relacją podtypu (tj.A ≤ B
Oznacza, żeA
jest podtypemB
), mamyf
jest kowariantny, jeśli toA ≤ B
sugerujef(A) ≤ f(B)
f
jest sprzeczne, jeśli toA ≤ B
sugerujef(B) ≤ f(A)
f
jest niezmienna, jeśli żadna z powyższych nie zachodziRozważmy przykład. Niech
f(A) = List<A>
gdzieList
jest zadeklarowane przezCzy jest
f
kowariantny, kontrawariantny czy niezmienny? Kowariantna oznaczałoby, żeList<String>
jest podtypemList<Object>
, kontrawariantny żeList<Object>
jest podtypemList<String>
i niezmienna, że nie jest podtypem druga, czyliList<String>
iList<Object>
są niewymienialne typy. W Javie to drugie jest prawdą, mówimy (nieco nieformalnie), że typy generyczne są niezmienne.Inny przykład. Niech
f(A) = A[]
. Czy jestf
kowariantny, kontrawariantny czy niezmienny? To znaczy, czy String [] jest podtypem Object [], Object [] jest podtypem String [], czy też nie jest podtypem drugiego? (Odpowiedź: w Javie tablice są kowariantne)To wciąż było raczej abstrakcyjne. Aby było to bardziej konkretne, przyjrzyjmy się, które operacje w Javie są zdefiniowane pod względem relacji podtypu. Najprostszym przykładem jest przydział. Twierdzenie
skompiluje się tylko wtedy, gdy
typeof(y) ≤ typeof(x)
. Oznacza to, że właśnie dowiedzieliśmy się, że oświadczenianie skompiluje się w Javie, ale
będzie.
Innym przykładem, w którym relacja podtypu ma znaczenie, jest wyrażenie wywołania metody:
Mówiąc nieformalnie, ta instrukcja jest oceniana przez przypisanie wartości
a
do pierwszego parametru metody, następnie wykonanie treści metody, a następnie przypisanie wartości zwracanej metodomresult
. Podobnie jak zwykłe przypisanie w ostatnim przykładzie, „prawa strona” musi być podtypem „lewej strony”, tj. To stwierdzenie może być ważne tylko wtedy, gdytypeof(a) ≤ typeof(parameter(method))
ireturntype(method) ≤ typeof(result)
. To znaczy, jeśli metoda jest zadeklarowana przez:żadne z poniższych wyrażeń nie zostanie skompilowane:
ale
będzie.
Kolejny przykład, w którym znaczenie ma podtytuł jest nadrzędne. Rozważać:
gdzie
Nieformalnie środowisko wykonawcze przepisze to do:
Aby zaznaczony wiersz został skompilowany, parametr metody przesłaniającej metody musi być nadtypem parametru metody zastępowanej metody, a typ zwracany jest podtypem metody przesłoniętej. Formalnie rzecz biorąc,
f(A) = parametertype(method asdeclaredin(A))
musi być przynajmniej kontrawariantna, a jeśli tof(A) = returntype(method asdeclaredin(A))
przynajmniej kowariantna.Zwróć uwagę na „co najmniej” powyżej. Są to minimalne wymagania, które będzie wymuszał każdy rozsądny, statycznie bezpieczny, obiektowy język programowania, ale język programowania może być bardziej rygorystyczny. W przypadku Javy 1.4 typy parametrów i zwracane metody muszą być identyczne (z wyjątkiem wymazywania typu) podczas przesłonięcia metod, tj.
parametertype(method asdeclaredin(A)) = parametertype(method asdeclaredin(B))
Podczas przesłaniania. Od wersji Java 1.5 kowariantne typy zwracane są dozwolone podczas zastępowania, tj. Następujące elementy będą kompilowane w Javie 1.5, ale nie w Javie 1.4:Mam nadzieję, że wszystko pokryłem - a raczej zarysowałem powierzchnię. Wciąż mam nadzieję, że pomoże to zrozumieć abstrakcyjną, ale ważną koncepcję wariancji typu.
źródło
A ≤ B
. Ta notacja sprawia, że rzeczy są znacznie prostsze i bardziej znaczące. Dobra lektura ...Biorąc system typów java, a następnie klasy:
Każdy obiekt pewnego typu T można zastąpić obiektem podtypu T.
RÓŻNORODNOŚĆ TYPU - METODY KLAS MAJĄ NASTĘPUJĄCE KONSEKWENCJE
Można zauważyć, że:
Teraz współ- i przeciwstawne temu, że B jest podtypem A. Następujące silniejsze typowania można wprowadzić z bardziej szczegółową wiedzą. W podtypie.
Kowariancja (dostępna w Javie) jest przydatna, aby powiedzieć, że zwraca się bardziej szczegółowy wynik w podtypie; szczególnie widoczne, gdy A = T i B = S. Contravariance mówi, że jesteś przygotowany na bardziej ogólny argument.
źródło
Wariancja dotyczy relacji między klasami o różnych parametrach ogólnych. Ich relacje są powodem, dla którego możemy je obsadzić.
Wariancja Co i Contra to całkiem logiczne rzeczy. System typów języka zmusza nas do wspierania logiki prawdziwego życia. Łatwo to zrozumieć na przykładzie.
Kowariancja
Na przykład chcesz kupić kwiat, a masz w swoim mieście dwa sklepy z kwiatami: sklep z różami i sklep ze stokrotkami.
Jeśli zapytasz kogoś „gdzie jest kwiaciarnia?” a ktoś ci powie, gdzie jest sklep z różami, czy byłoby dobrze? tak, ponieważ róża to kwiat, jeśli chcesz kupić kwiat, możesz kupić różę. To samo dotyczy sytuacji, gdy ktoś przesłał Ci adres sklepu ze stokrotkami. To jest przykład kowariancji : możesz rzutować
A<C>
naA<B>
, gdzieC
jest podklasąB
, ifA
generuje wartości ogólne (zwraca jako wynik funkcji). Kowariancja dotyczy producentów.Rodzaje:
Pytanie brzmi „gdzie jest kwiaciarnia?”, Odpowiedź brzmi „tam sklep z różami”:
Sprzeczność
Na przykład chcesz podarować kwiat swojej dziewczynie. Jeśli twoja dziewczyna kocha każdy kwiat, czy możesz uważać ją za osobę, która kocha róże, czy osobę, która kocha stokrotki? tak, ponieważ gdyby kochała jakikolwiek kwiat, pokochałaby zarówno różę, jak i stokrotkę. To jest przykład kontrawariancji : możesz rzucać
A<B>
doA<C>
, gdzieC
jest podklasaB
, jeśliA
zużywa wartość ogólną. Kontrawariancja dotyczy konsumentów.Rodzaje:
Uważasz swoją dziewczynę, która kocha każdy kwiat, za kogoś, kto kocha róże i dajesz jej różę:
Więcej można znaleźć w Źródle .
źródło