Wątpię, żeby była jakaś różnica. Myślę, że to tylko nazwa tego parametru typu. A czy ostatni jest nawet ważny?
CodesInChaos
Odpowiedzi:
231
Cóż, nie ma różnicy między pierwszymi dwoma - po prostu używają różnych nazw dla parametru type ( Elub T).
Trzecia nie jest prawidłową deklaracją - ?jest używana jako symbol wieloznaczny, który jest używany, gdy podaje się argument typu , np. List<?> foo = ...Oznacza, że fooodnosi się do listy jakiegoś typu, ale nie wiemy co.
Wszystko to jest ogólne , co jest dość dużym tematem. Możesz dowiedzieć się o tym za pomocą następujących zasobów, chociaż oczywiście dostępnych jest więcej:
Wygląda na to, że link do pliku PDF jest uszkodzony. Znalazłem tutaj kopię , która wydaje się być kopią , ale nie mogę być w 100% pewien, ponieważ nie wiem, jak wyglądał oryginał.
John
2
@John: Tak, to jest to. Zredaguje link, czy to ten, czy Oracle ...
Jon Skeet
Czy jest coś innego niż T, E i? używane w lekach generycznych? Jeśli tak, czym one są i co one oznaczają?
sofs1
1
@ sofs1: Nie ma w tym nic specjalnego Ti E- to tylko identyfikatory. Możesz KeyValuePair<K, V>na przykład pisać . ?ma jednak szczególne znaczenie.
Jon Skeet
215
To bardziej konwencja niż cokolwiek innego.
T ma być typem
Ema być elementem ( List<E>: lista elementów)
Kjest kluczem (w Map<K,V>)
V to Wartość (jako wartość zwracana lub wartość odwzorowana)
Są one w pełni zamienne (pomimo konfliktów w tej samej deklaracji).
Litera między <> to tylko nazwa. W odpowiedzi opisujesz tylko konwencje. Nie musi to być nawet jedna wielka litera; możesz użyć dowolnej nazwy, tak jak możesz nadać klasy, zmienne itp. dowolną nazwę.
Poprzednie odpowiedzi wyjaśniają parametry typu (T, E itp.), Ale nie wyjaśniają symboli wieloznacznych „?” Ani różnic między nimi, więc zajmę się tym.
Po pierwsze, żeby być jasnym: symbole wieloznaczne i parametry typu nie są takie same. Gdy parametry typu definiują rodzaj zmiennej (np. T), która reprezentuje typ dla zakresu, symbol wieloznaczny nie: symbol wieloznaczny po prostu określa zestaw dopuszczalnych typów, których można użyć dla typu ogólnego. Bez żadnych ograniczeń ( extendslub super), symbol wieloznaczny oznacza „użyj tutaj dowolnego typu”.
Symbol wieloznaczny zawsze znajduje się między nawiasami kątowymi i ma znaczenie tylko w kontekście typu ogólnego:
publicvoid foo(List<?> listOfAnyType){...}// pass a List of any type
nigdy
public<?>? bar(? someType){...}// error. Must use type params here
Staje się bardziej mylące, gdy się pokrywają. Na przykład:
List<T> fooList;// A list which will be of type T, when T is chosen.// Requires T was defined above in this scopeList<?> barList;// A list of some type, decided elsewhere. You can do// this anywhere, no T required.
Definicje metod nakładają się na siebie. Są funkcjonalnie identyczne:
Jeśli więc zachodzą na siebie, po co korzystać z jednego lub drugiego? Czasami jest to po prostu styl: niektórzy twierdzą, że jeśli nie potrzebujesz parametru typu, powinieneś użyć symbolu wieloznacznego, aby kod był prostszy / bardziej czytelny. Jedną główną różnicę wyjaśniłem powyżej: parametry par definiują zmienną typu (np. T), której można użyć w innym miejscu zakresu; symbol wieloznaczny nie. W przeciwnym razie istnieją dwie duże różnice między parametrami typu a symbolem wieloznacznym:
Parametry typu mogą mieć wiele klas granicznych; symbol wieloznaczny nie może:
Symbol wieloznaczny może mieć dolne granice; parametry typu nie mogą:
publicvoid bar(List<?superInteger> list){...}
W powyższym List<? super Integer>zdefiniowano Integerdolną granicę symbolu wieloznacznego, co oznacza, że typem listy musi być liczba całkowita lub supertyp typu liczba całkowita. Granice typów ogólnych wykraczają poza to, co chcę szczegółowo omówić. Krótko mówiąc, pozwala określić, jakie typy mogą być typami ogólnymi. Dzięki temu można traktować leki generyczne polimorficznie. Np. Z:
publicvoid foo(List<?extendsNumber> numbers){...}
Można przekazać List<Integer>, List<Float>, List<Byte>, itd. Dla numbers. Bez ograniczania typów to nie zadziała - takie właśnie są ogólne.
Na koniec, oto definicja metody, która używa znaku wieloznacznego do zrobienia czegoś, czego nie sądzę, że można zrobić w inny sposób:
numberSupermoże być liczbą lub dowolnym nadtypem liczby (np. List<Object>) i elemmusi być liczbą lub dowolnym podtypem. Przy wszystkich ograniczeniach kompilator może być pewien, że .add()jest bezpieczny.
„public void foo (List <? extends Number> numbers) {...}” czy „extends” powinno być „super”?
1a1a11a
1
Nie. Celem tego przykładu jest pokazanie podpisu, który polimorficznie obsługuje Listę Liczby i podtypy Liczby. W tym celu używasz „rozszerzeń”. Tj. „Przekaż mi Listę liczby lub cokolwiek, co rozszerza liczbę” (List <Integer>, List <Float>, cokolwiek). Taka metoda może następnie iterować listę i dla każdego elementu „e” wykonać np. E.floatValue (). Nie ma znaczenia, jaki podtyp (rozszerzenie) przekazywanej liczby - zawsze będziesz w stanie „.floatValue ()”, ponieważ .floatValue () jest metodą liczby.
Hawkeye Parker
W ostatnim przykładzie „List <? Super Number>” może po prostu być „List <Number>”, ponieważ metoda nie pozwala na nic bardziej ogólnego.
jessarah
@jessarah nope. Być może mój przykład jest niejasny, ale w tym przykładzie wspominam, że adder () może przyjąć List <Object> (Object jest nadklasą Liczby). Jeśli chcesz, aby mógł to zrobić, musi mieć podpis „Lista <? Super numer>”. Właśnie o to chodzi tutaj w „super”.
Hawkeye Parker,
2
Ta odpowiedź bardzo dobrze wyjaśnia różnice między symbolami wieloznacznymi a parametrami typu, powinno być jedno dedykowane pytanie z tą odpowiedzią. Ostatnio sięgam głębiej w generics i ta odpowiedź bardzo mi pomogła w zestawieniu, wiele precyzyjnych informacji w skrócie, dzięki!
Testo Testini
27
Zmienna typu, <T>, może być dowolnym nie-pierwotnym typem, który określisz: dowolnym typem klasy, dowolnym typem interfejsu, dowolnym typem tablicy, a nawet inną zmienną typu.
Najczęściej używane nazwy parametrów typu to:
E - Element (szeroko stosowany w ramach Java Collections Framework)
K - Klucz
N - liczba
T - typ
V - wartość
W Javie 7 dozwolone jest tworzenie instancji w następujący sposób:
Odpowiedzi:
Cóż, nie ma różnicy między pierwszymi dwoma - po prostu używają różnych nazw dla parametru type (
E
lubT
).Trzecia nie jest prawidłową deklaracją -
?
jest używana jako symbol wieloznaczny, który jest używany, gdy podaje się argument typu , np.List<?> foo = ...
Oznacza, żefoo
odnosi się do listy jakiegoś typu, ale nie wiemy co.Wszystko to jest ogólne , co jest dość dużym tematem. Możesz dowiedzieć się o tym za pomocą następujących zasobów, chociaż oczywiście dostępnych jest więcej:
źródło
T
iE
- to tylko identyfikatory. MożeszKeyValuePair<K, V>
na przykład pisać .?
ma jednak szczególne znaczenie.To bardziej konwencja niż cokolwiek innego.
T
ma być typemE
ma być elementem (List<E>
: lista elementów)K
jest kluczem (wMap<K,V>
)V
to Wartość (jako wartość zwracana lub wartość odwzorowana)Są one w pełni zamienne (pomimo konfliktów w tej samej deklaracji).
źródło
Poprzednie odpowiedzi wyjaśniają parametry typu (T, E itp.), Ale nie wyjaśniają symboli wieloznacznych „?” Ani różnic między nimi, więc zajmę się tym.
Po pierwsze, żeby być jasnym: symbole wieloznaczne i parametry typu nie są takie same. Gdy parametry typu definiują rodzaj zmiennej (np. T), która reprezentuje typ dla zakresu, symbol wieloznaczny nie: symbol wieloznaczny po prostu określa zestaw dopuszczalnych typów, których można użyć dla typu ogólnego. Bez żadnych ograniczeń (
extends
lubsuper
), symbol wieloznaczny oznacza „użyj tutaj dowolnego typu”.Symbol wieloznaczny zawsze znajduje się między nawiasami kątowymi i ma znaczenie tylko w kontekście typu ogólnego:
nigdy
lub
Staje się bardziej mylące, gdy się pokrywają. Na przykład:
Definicje metod nakładają się na siebie. Są funkcjonalnie identyczne:
Jeśli więc zachodzą na siebie, po co korzystać z jednego lub drugiego? Czasami jest to po prostu styl: niektórzy twierdzą, że jeśli nie potrzebujesz parametru typu, powinieneś użyć symbolu wieloznacznego, aby kod był prostszy / bardziej czytelny. Jedną główną różnicę wyjaśniłem powyżej: parametry par definiują zmienną typu (np. T), której można użyć w innym miejscu zakresu; symbol wieloznaczny nie. W przeciwnym razie istnieją dwie duże różnice między parametrami typu a symbolem wieloznacznym:
Parametry typu mogą mieć wiele klas granicznych; symbol wieloznaczny nie może:
Symbol wieloznaczny może mieć dolne granice; parametry typu nie mogą:
W powyższym
List<? super Integer>
zdefiniowanoInteger
dolną granicę symbolu wieloznacznego, co oznacza, że typem listy musi być liczba całkowita lub supertyp typu liczba całkowita. Granice typów ogólnych wykraczają poza to, co chcę szczegółowo omówić. Krótko mówiąc, pozwala określić, jakie typy mogą być typami ogólnymi. Dzięki temu można traktować leki generyczne polimorficznie. Np. Z:Można przekazać
List<Integer>
,List<Float>
,List<Byte>
, itd. Dlanumbers
. Bez ograniczania typów to nie zadziała - takie właśnie są ogólne.Na koniec, oto definicja metody, która używa znaku wieloznacznego do zrobienia czegoś, czego nie sądzę, że można zrobić w inny sposób:
numberSuper
może być liczbą lub dowolnym nadtypem liczby (np.List<Object>
) ielem
musi być liczbą lub dowolnym podtypem. Przy wszystkich ograniczeniach kompilator może być pewien, że.add()
jest bezpieczny.źródło
Zmienna typu, <T>, może być dowolnym nie-pierwotnym typem, który określisz: dowolnym typem klasy, dowolnym typem interfejsu, dowolnym typem tablicy, a nawet inną zmienną typu.
Najczęściej używane nazwy parametrów typu to:
W Javie 7 dozwolone jest tworzenie instancji w następujący sposób:
źródło
Najczęściej używane nazwy parametrów typu to:
Zobaczysz te nazwy używane w interfejsie API Java SE
źródło
kompilator wykona przechwytywanie dla każdego znaku wieloznacznego (np. znaku zapytania na liście), gdy utworzy funkcję taką jak:
Jednak ogólny typ, taki jak V, byłby w porządku i czyniąc go ogólną metodą :
źródło