Jaka jest różnica między "E", " T "i"? dla Java generics?

Natknąłem się na kod Javy tak:

public interface Foo<E> {}

public interface Bar<T> {}

public interface Zar<?> {}

Jaka jest różnica pomiędzy wszystkimi trzema powyższymi i jak nazywają tego typu deklaracje klas lub interfejsów w Javie?

 281
Author: Isaac Moore, 2011-05-15

6 answers

Cóż, nie ma różnicy między dwoma pierwszymi - używają tylko różnych nazw dla parametru typu (E LUB T).

Trzecia nie jest poprawną deklaracją - ? jest używana jakosymbol wieloznaczny , który jest używany podczas podawania argumentu type , np. List<?> foo = ... oznacza, że foo odnosi się do listy jakiegoś typu, ale nie wiemy co.

Wszystko to jest generyki , co jest dość dużym tematem. Możesz chcieć dowiedzieć się o tym poprzez następujące zasoby, choć oczywiście jest ich więcej:

 249
Author: Jon Skeet,
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-30 17:03:52

To bardziej konwencja niż cokolwiek innego.

  • T ma być typem
  • E ma być elementem (List<E>: Lista elementów)
  • K jest kluczem (w Map<K,V>)
  • V jest wartością (jako wartość zwracaną lub mapowaną)

Są w pełni wymienne (niezależnie od konfliktów w tej samej deklaracji).

 227
Author: ratchet freak,
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-11-09 14:29:39

Poprzednie odpowiedzi wyjaśniają parametry typu (T, E, itd.), ale nie Tłumacz dziką kartą"?", lub różnice między nimi, więc zajmę się tym.

Po pierwsze, żeby było jasne: symbole wieloznaczne i parametry typu nie są takie same. Tam, gdzie parametry typu definiują rodzaj zmiennej (np. T), która reprezentuje typ dla zakresu, symbol wieloznaczny tego nie robi: symbol wieloznaczny definiuje tylko zbiór dozwolonych typów, których można użyć dla typu ogólnego. Bez ograniczeń (extends lub super), wildcard oznacza "użyj dowolnego typu tutaj".

Symbole wieloznaczne zawsze znajdują się między nawiasami kątowymi i mają znaczenie tylko w kontekście typu ogólnego:

public void foo(List<?> listOfAnyType) {...}  // pass a List of any type

Nigdy

public <?> ? bar(? someType) {...}  // error. Must use type params here

Lub

public class MyGeneric ? {      // error
    public ? getFoo() { ... }   // error
    ...
}
Tam, gdzie się pokrywają, robi się coraz bardziej mylące. 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 scope
List<?> barList;  // A list of some type, decided elsewhere. You can do
                  // this anywhere, no T required.

Istnieje wiele nakładania się tego, co jest możliwe z definicjami metod. Następujące są funkcjonalnie identyczne:

public <T> void foo(List<T> listOfT) {...}
public void bar(List<?> listOfSomething)  {...}

Więc, jeśli istnieje nakładanie się, po co używać jednego lub drugiego? Czasami, szczerze mówiąc, to tylko styl: niektórzy mówią, że jeśli nie potrzebujesz param typu, powinieneś użyć symbolu wieloznacznego, aby Kod był prostszy/bardziej czytelny. Jedna główna różnica, którą wyjaśniłem powyżej: params typu definiuje zmienną typu (np. T), której można użyć gdzie indziej w zakresie; wildcard Nie. w przeciwnym razie istnieją dwie duże różnice między params typu a wildcard: {]}

Params typu może mieć wiele klas obwiedni; symbol wieloznaczny nie może:

public class Foo <T extends Comparable<T> & Cloneable> {...}

The symbole wieloznaczne mogą mieć niższe granice; params typu nie może:

public void bar(List<? super Integer> list) {...}

W powyższym List<? super Integer> definiuje Integer jako dolną granicę na symbolu wieloznacznym, co oznacza, że typ listy musi być liczbą całkowitą lub super-typem liczby całkowitej. Rodzajowe ograniczanie jest poza tym, co chcę szczegółowo omówić. Krótko mówiąc, pozwala zdefiniować jakie typy może być typem generycznym. Dzięki temu możliwe jest polimorficzne leczenie leków generycznych. Np. z:

public void foo(List<? extends Number> numbers) {...}

Możesz zdać List<Integer>, List<Float>, List<Byte>, itd. dla numbers. Bez ograniczania typów to nie zadziała . takie są generyki.

Na koniec, oto definicja metody, która używa wieloznacznych znaków, aby zrobić coś, czego nie możesz zrobić w inny sposób: {]}

public static <T extends Number> void adder(T elem, List<? super Number> numberSuper) {
    numberSuper.add(elem);
}

numberSuper Może być listą liczby lub dowolnym supertyp liczby (np. List<Object>), a elem musi być liczbą lub dowolnym podtypem. Przy wszystkich obwiedniach kompilator może być pewien, że {[20] } jest typesafe.

 141
Author: Hawkeye Parker,
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
2016-10-13 20:37:54

Zmienna typu, , może być dowolnym typem Nie-prymitywnym: dowolnym typem klasy, dowolnym typem interfejsu, dowolnym typem tablicy lub nawet inną zmienną typu.

Najczęściej używane nazwy parametrów typu to:

    E-Element (szeroko stosowany przez framework zbiorów Javy)
  • K - Key
  • N-Liczba
  • T - Type
  • V - Wartość

W Javie 7 dozwolone jest tworzenie instancji w następujący sposób:

Foo<String, Integer> foo = new Foo<>(); // Java 7
Foo<String, Integer> foo = new Foo<String, Integer>(); // Java 6
 29
Author: Uva,
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-09-29 22:30:21

Najczęściej używane nazwy parametrów typu to:

E - Element (used extensively by the Java Collections Framework)
K - Key
N - Number
T - Type
V - Value
S,U,V etc. - 2nd, 3rd, 4th types

Zobaczysz te nazwy używane w API Java SE

 6
Author: Waqas Ahmed,
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
2019-05-17 16:03:09

Kompilator wykona przechwytywanie dla każdego znaku wieloznacznego (np. znak zapytania na liście), gdy tworzy funkcję taką jak:

foo(List<?> list) {
    list.put(list.get()) // ERROR: capture and Object are not identical type.
}

Jednak Typ generyczny, taki jak V, byłby w porządku i czyniłby go metodą generyczną :

<V>void foo(List<V> list) {
    list.put(list.get())
}
 4
Author: Tiina,
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-04-27 06:58:28