2015-01-08 16 views
5

Jaki jest cel użycia symbolu wieloznacznego w przypadku generałów nieograniczonych lub o górnych ograniczeniach? Dokładniej:Generic Java - cel symboli wieloznacznych z wyjątkiem niższych granic?

Dlaczego miałbym powiedzieć public static void foo(List<?> bar) zamiast public static <E> void foo(List<E> bar)?

Dlaczego miałbym powiedzieć public static void foo(List<? extends Baz> bar) zamiast public static <E extends Baz> void foo(List<E> bar)?

+0

Zwięzłość, może? – aroth

Odpowiedz

2

Korzystne są wersje z zamiennika. Jeśli parametr ma typ List<?>, oczywiste jest, że dowolny List zostanie zaakceptowany. Jeśli akceptowany jest dowolny List, nie ma powodu, aby nadawać parametrowi typu nazwę, więc pisanie <E> będzie po prostu bałaganem. Z drugiej strony, jeśli parametr typu pojawia się dwa razy w podpisie, nie można używać symboli wieloznacznych. Na przykład ta sygnatura wymaga parametru typu.

public static <E> List<E> combineLists(List<E> list1, List<E> list2) 

Właściwie w tym przykładzie będzie prawdopodobnie lepiej, gdyby argumenty musiały wpisać List<? extends E> (jedynym sposobem, aby to zrobić bez symboli wieloznacznych byłoby mieć trzy parametry typu, totalny bałagan).

W efektywnej Javie zaleca się, że nawet jeśli parametr typu jest potrzebny w treści metody, powinieneś preferować wersję podpisu z symbolem wieloznacznym i napisać prywatną metodę pomocnika, aby było to możliwe. Na przykład:

public static void swapFirstAndLast(List<?> list) { 
    helper(list); 
} 

private static <E> void helper(List<E> list) { 
    int size = list.size(); 
    E e = list.get(0); 
    list.set(0, list.get(size - 1)); // These lines would not be possible 
    list.set(size - 1, e);   // If the type of list were List<?> 
} 
+0

Wszędzie oprócz faktycznego parametru typu można umieścić symbol wieloznaczny. Oznacza to, że podczas, gdy jest to poprawna składnia: 'public staticList CombineLists (List list1, List list2)', będziesz nienawidzić się za próbowanie wdrożenia tego. – Makoto

4

Jeśli nie zamierzasz odnieść się do kodu E w poniższym kodzie, nie ma potrzeby zadeklarowania go.

Zmniejsza obciążenie pamięci programatora.

+1

Tak, dokładnie to, co zamierzałem powiedzieć. Typ ogólny jest po to, aby dać ci siłę, by ZROBIĆ z nim coś, a nie tak naprawdę jako cukier syntaktyczny. – asteri

2

Jeśli typ listy zostanie ustalony w czasie wykonywania, konieczne będzie użycie symboli wieloznacznych.

Poniższy program wypisze List<String>, jeśli zostanie uruchomiony z dowolnymi argumentami wiersza poleceń; inaczej będzie wydrukować List<Number>:

public class Test { 

    public static List<String> listOfStrings = Arrays.asList("hello", "world"); 
    public static List<Number> listOfNumbers = Arrays.asList(1, 2, 3, 4.5); 

    public static List<?> getListOfUnknown(boolean arg) { 
     if(arg) return listOfStrings; 
     else return listOfNumbers; 
    } 

    public static void main(String[] args) { 
     System.out.println(getListOfUnknown(args.length > 0)); 
    } 
} 
+0

Korzystając z linii rozumowania OP, można zrobić coś takiego: 'public List getListOfUnknown (boolean arg)'. Nie żebym to polecał. – asteri

+0

@asteri, ale wtedy musisz wywołać ' getListOfUnknown' lub' getListOfUnknown', ponieważ 'T' musi być znane podczas kompilacji. – immibis

+0

Ah, widzę, co mówisz. Przepraszam, właśnie przeczytałem podpis metody, a nie treść metody. Mój błąd. – asteri

Powiązane problemy