2008-09-16 21 views
9
public static void main(String[] args) { 

    List<? extends Object> mylist = new ArrayList<Object>(); 

    mylist.add("Java"); // compile error 

} 

Powyższy kod nie pozwala na dodawanie elementów do listy, a dzikie karty mogą być używane tylko jako podpis w metodach, również nie do dodawania, ale tylko do uzyskiwania dostępu. W tym przypadku, jaki jest cel powyższego celu?Kolekcje Java za pomocą symbolu wieloznacznego

Odpowiedz

5

Powiedzmy masz interfejs i dwie klasy:

interface IResult {} 
class AResult implements IResult {} 
class BResult implements IResult {} 

wtedy masz klasy, które zwróci listę jako wynik:

interface ITest<T extends IResult> { 
    List<T> getResult(); 
} 

class ATest implements ITest<AResult> { 
    // look, overridden! 
    List<AResult> getResult(); 
} 

class BTest implements ITest<BResult> { 
    // overridden again! 
    List<BResult> getResult(); 
} 

Jest to dobre rozwiązanie, gdy trzeba „kowariantna zwraca ", ale zwracasz kolekcje zamiast własnych obiektów. Dużym plusem jest to, że nie musisz rzucać obiektami podczas używania ATest i BTest niezależnie od interfejsu ITest. Jednak przy korzystaniu z interfejsu ITest nie możesz niczego dodać do listy, która została zwrócona - ponieważ nie możesz określić, jakie typy obiektów lista naprawdę zawiera! Jeśli byłoby to dozwolone, będzie można dodać do listy BResult <aresult> (zwracane jako Lista <? Rozciąga T >), która nie ma żadnego sensu.

Więc trzeba o tym pamiętać: Lista <? rozszerza X > definiuje listę, która może być łatwo zastąpiona, ale która jest tylko do odczytu.

1

W przypadku generycznych java używających symboli wieloznacznych, możesz otrzymać powyższą deklarację, zakładając, że będziesz tylko czytać z niej.

Nie możesz dodawać/zapisywać do niego, ponieważ wszystkie typy ogólne muszą być usunięte w czasie kompilacji, a podczas kompilacji nie ma sposobu, który kompilator wie. Lista to tylko ciągi znaków (może to być dowolny obiekt zawierający ciągi!)

Można jednak czytać z niego, ponieważ będą to przynajmniej obiekty. Mieszanie różnych typów nie jest dozwolone w kolekcjach java, aby zachować czystość i zrozumiałość, a to pomaga zapewnić to.

+0

Nie, to nie w porządku. Przynajmniej z drugiego akapitu wyjaśnienia nie ma tematu. Tu nie chodzi o wymazywanie typu. – jrudolph

+0

Również akapit pierwszy jest nieprawidłowy. Możesz usunąć lub dodać wartość null do listy, jak zadeklarowano w pytaniu, możesz także dodać odniesienia (bez wartości null), jeśli symbol wieloznaczny jest zdefiniowany jako super-granica. –

1

Punkt ograniczonych typów symboli wieloznacznych polega na ich użyciu w sygnaturach metod w celu zwiększenia elastyczności interfejsu API. Jeśli, na przykład, zaimplementować rodzajowe Stack<E>, można dostarczyć metody push szereg elementów do stosu tak:

public void pushAll(Iterable<? extends E> elements) { 
    for(E element : elements){ 
     push(e); 
    } 
} 

porównaniu do pushAll(Iterable<E> elements) podpisanie bez zamiennika ma to tę zaletę, że umożliwia przekazywanie kolekcji podtypów E do metody - normalnie nie byłoby to dozwolone, ponieważ Iterable<String> jest, w pewnym stopniu sprzeczna z intuicją, nie jest podklasą Iterable<Object>.

0

to działa:

List<? super Object> mylist = new ArrayList<Object>(); 
mylist.add("Java"); // no compile error 

Od O'Reilly Java Generics:

Get i Put Zasada: użyć rozciąga wieloznaczny kiedy można dostać tylko wartości nasze struktury, należy użyć super wieloznacznego kiedy tylko wstawiasz wartości do struktury i nie używasz symbolu wieloznacznego, który dostajesz i umieszczasz.

+0

Myślę, że miałeś na myśli 'List '. –

+0

Nie. Powtórzyłem powyższy przykład i zastąpiłem "extends" przez "super". To jest to! –

+1

PECS = producent rozszerza, konsument super – helpermethod

5

W swojej książce "Skuteczne Jawy" (wydanie drugie) Joshua Bloch wyjaśnia, co nazywa zasadą producenta/konsumenta w odniesieniu do używania leków generycznych. wyjaśnieniu Josha powinien powiedzieć, dlaczego Twój przykład nie działa (kompilacji) ...

Rozdział 5 (rodzajowych) jest swobodnie dostępny tutaj: http://java.sun.com/docs/books/effective/generics.pdf

Więcej informacji o książce (i autora) dostępne są: http://java.sun.com/docs/books/effective/

0

List<? extends Object>, która jest taka sama jak List<?> spełnia cel uogólniając wszystkie typy List<String>, List<Number>, List<Object> itp (tak, wszystkie typy z właściwego typu w miejscu ?). Wartości wszystkich tych typów można przypisać do zmiennej o typie List<?> (gdzie różni się ona od List<Object>!).

Ogólnie nie można dodać ciągu do takiej listy. Jednak z listy można odczytać numer Object i można do niego dodać null. Możesz także obliczyć długość listy itp. Są to operacje, które gwarantują działanie dla każdego z tych typów.

Na dobry wstęp do symboli wieloznacznych, zobacz papier Adding Wildcards to the Java Programming Language. Jest to praca akademicka, ale nadal bardzo dostępna.

0

Java rodzajowych: Dzikie karty w kolekcjach

  1. rozciąga
  2. Super
  3. ?

Dziś wyjaśnię, jak przydatne są dzikie karty. Aby zrozumieć pojęcie to jest trochę trudne

Teraz Załóżmy, że masz klasę abstrakcyjną i że trzeba abstrakcyjny metodę zwaną paintObject().

Now you want to use different type of collection in every child class. 

Poniżej znajduje się metoda AbstractMain.

Oto kroki podjęliśmy dla tej metody Streszczenie Głównym

1. stworzyliśmy abstrakcyjne klasy

2. w parametrze musimy zdefiniować T (można użyć dowolnego znaku) - W tym przypadku dowolna klasa implementująca tę metodę może użyć dowolnego typu klasy. np. Klasa może implementować metody takie jak public void paintObject obiektu ArrayList() lub public void paintObject (Object Hashset)

3. I Użyliśmy również E rozciąga MainColorTO - W tym przypadku E rozciąga MainColorTo - To wyraźnie oznacza którykolwiek klasa chcesz użyć, które muszą być sub klasa MainColorTo

4. Musimy zdefiniować abstrakcyjną metodę zwaną paintObject (T obiekt, E objectTO) --Now tutaj cokolwiek klasa jest wdrożenie metody, która metoda może użyć dowolnej klasy na pierwszy argument i drugiego parametru, że metoda ma użyć typu z MainColorTO

public abstract class AbstractMain<T,E extends MainColorTO> { 
     public abstract void paintObject(T Object,E TO); 
} 

Teraz będziemy rozszerzać klasę abstrakcyjną i implementować metodę poniżej klasy np.

public class MainColorTO { 
    public void paintColor(){ 
      System.out.println("Paint Color........"); 
    } 
    } 

public class RedTO extends MainColorTO { 
    @Override 
    public void paintColor() { 
    System.out.println("RedTO......"); 
} 
} 
public class WhiteTO extends MainColorTO { 
    @Override 
    public void paintColor() { 
    System.out.println("White TO......"); 
    } 
} 

Teraz weźmiemy dwa przykłady.

1.PaintHome.java

public class PaintHome extends AbstractMain<ArrayList, RedTO> { 
    @Override 
    public void paintObject(ArrayList arrayList,RedTO red) { 
     System.out.println(arrayList); 

    } 
} 

Teraz w wyżej PaintHome.java można sprawdzić, że użyliśmy ArrayList w pierwszym argumencie (Jak możemy podjąć każdą klasę) oraz w drugim argumencie użyliśmy RedTO (który rozciąga MainColorTO)

2.PaintCar.java

public class PaintCar extends AbstractMain<HashSet, WhiteTO>{ 
    @Override 
    public void paintObject(HashSet Object,WhiteTO white) { 
     System.out.println(Object); 

    } 
} 

Teraz w powyższym PaintCar.java można sprawdzić, że użyliśmy HashSet w pierwszym argumencie (Jak możemy podjąć żadnej klasy) oraz w drugim argumencie użyliśmy WhiteTO (który rozszerza MainColorTO)

Ponint uczuć nie można użyć słowa kluczowego super na poziomie klasy można użyć tylko rozszerza słowa kluczowego na poziomie klasy defination

public abstract class AbstractMain<P,E super MainColorTO> { 

    public abstract void paintObject(P Object,E TO); 

} 

Powyższy kod daje błąd kompilatora.

Powiązane problemy