Różnica między typem generycznym a typem wieloznacznym
Jestem nowicjuszem w Generic i moje pytanie brzmi: jaka jest różnica między dwoma funkcjami:
Funkcja 1:
public static <E> void funct1 (List<E> list1) {
}
Funkcja 2:
public static void funct2(List<?> list) {
}
Dzięki. 7 answers
Pierwszy podpis mówi: list1 jest listą Es.
Drugi podpis mówi: list jest listą instancji jakiegoś typu, ale nie znamy tego typu.
Różnica staje się oczywista, gdy próbujemy zmienić metodę, więc potrzeba drugiego argumentu, który należy dodać do listy wewnątrz metody:
import java.util.List;
public class Experiment {
public static <E> void funct1(final List<E> list1, final E something) {
list1.add(something);
}
public static void funct2(final List<?> list, final Object something) {
list.add(something); // does not compile
}
}
Pierwszy działa ładnie. I nie można zmienić drugiego argumentu na coś, co faktycznie się skompiluje.
Właśnie znalazłem jeszcze ładniejszy demonstracja różnicy:
public class Experiment {
public static <E> void funct1(final List<E> list) {
list.add(list.get(0));
}
public static void funct2(final List<?> list) {
list.add(list.get(0)); // !!!!!!!!!!!!!! won't compile !!!!!!!!!
}
}
Może być po co nam <?>
, skoro ogranicza to tylko to ,co możemy z nim zrobić (tak jak zrobił to @Babu_Reddy_H w komentarzach). Widzę następujące zalety wersji wildcard:
-
Rozmówca musi wiedzieć mniej o obiekcie, który przechodzi. Na przykład, jeśli mam mapę List:
Map<String, List<?>>
mogę przekazać jej wartości do funkcji bez określania typu elementów listy. Więc Jeśli rozdam przedmioty tak sparametryzowany aktywnie ograniczam to, co ludzie wiedzą o tych obiektach i co mogą z nimi zrobić (o ile trzymają się z dala od niebezpiecznego rzucania).
Te dwa mają sens, gdy je łączę: List<? extends T>
. Na przykład rozważ metodę List<T> merge(List<? extends T>, List<? extends T>)
, która łączy dwie listy wejściowe z nową listą wyników. Pewnie, że możesz wprowadzić jeszcze dwa parametry typu, ale po co? To byłby koniec precyzowania rzeczy.
- w końcu wildcards mogą mieć niższe granice, więc dzięki listom możesz sprawić, że metoda
add
zadziała, podczas gdyget
nie daje Ci niczego użytecznego. Oczywiście rodzi to kolejne pytanie: dlaczego leki generyczne nie mają niższych granic?
Aby uzyskać bardziej szczegółową odpowiedź zobacz: kiedy stosować metody generyczne, a kiedy stosować wild-card? i http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeArguments.html#FAQ203
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:34
Generyki sprawiają, że zbiór jest bardziej bezpieczny.
List<E>
: E tutaj jest parametr Type, który może być użyty do określenia typu zawartości listy, ale był sposób No
, aby sprawdzić, jaka była zawartość podczas runtime
.
Generics are checked only during compilation time.
<? extends String>
: zostało to specjalnie wbudowane w Javę, aby poradzić sobie z problemem, który był z parametrem Type. "? extends String"
oznacza, że lista ta może mieć
objects which IS-A String.
Dla NP:
Klasa zwierząt Dog class extends Animal Klasa tygrysa extends Animal
Więc użycie "public void go(ArrayList<Animal> a)"
będzie NOT accept
psem lub Tygrysem jako jego treścią, ale zwierzęciem.
"public void go(ArrayList<? extends Animal> a)"
jest co jest potrzebne, aby ArrayList take in Dog and Tiger type.
Sprawdź, czy nie ma odniesień w Head First Java.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-08 05:03:54
Pierwsza jest funkcją, która przyjmuje parametr, który musi być listą pozycji typu E.
Drugi przykładowy Typ nie jest zdefiniowany
List<?> list
Więc możesz przekazać listę dowolnego typu obiektów.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-08 05:21:32
Lista jako typ parametru mówi, że parametr musi być listą elementów z dowolnym typem obiektu. Co więcej, można powiązać parametr E
, aby zadeklarować odniesienia do elementów listy wewnątrz ciała funkcji.
Lista jako typ parametru ma taką samą semantykę, z tą różnicą, że nie ma innego sposobu deklarowania odniesień do pozycji na liście niż użycie Object
. Inne posty dają dodatkowe subtelne różnice.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-07 13:48:58
Zwykle wyjaśniam różnicę między E > a ? > przez porównanie z kwantyfikacjami logicznymi, czyli kwantyfikacją uniwersalną i kwantyfikacją egzystencjalną.
- odpowiada "forall E,..."
- odpowiada "istnieje coś (oznaczonego ) takiego, że ...."
Dlatego następująca deklaracja metody ogólnej oznacza, że dla wszystkich typów klasy E definiujemy funct1
public static <E> void funct1 (List<E>; list1) {
}
Następujący rodzajnik deklaracja metody oznacza, że dla jakiejś istniejącej klasy oznaczonej przez ?>, definiujemy funct2
.
public static void funct2(List<?> list) {
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-16 10:54:36
(od czasu edycji) te dwie sygnatury funkcji mają taki sam efekt w kodzie zewnętrznym - obie przyjmują dowolny List
jako argument. Symbol wieloznaczny jest odpowiednikiem parametru typ, który jest używany tylko raz.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-08 07:28:38
Oprócz wyżej wymienionych różnic, istnieje również dodatkowa różnica: możesz jawnie ustawić argumenty typu dla wywołania metody generycznej:
List<Apple> apples = ...
ClassName.<Banana>funct2(apples); // for some reason the compiler seems to be ok
// with type parameters, even though the method has none
ClassName.<Banana>funct1(apples); // compiler error: incompatible types: List<Apple>
// cannot be converted to List<Banana>
(ClassName
jest nazwą klasy zawierającej metody.)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-24 10:32:08