2015-01-02 15 views
7

Niedawno uczę się języka Java Generics, a po prostu próbuję przejść przez "Java Generics FAQ".Java Generics Wildcard zamieszanie

Poniżej pytanie (# 304) dotyczące typu z parametryzacją typu wildcard, wprawiło mnie w zakłopotanie, doceniłbym Twoją pomoc.

Kod Przykład:

class Box<T> { 
    private T t; 
    public Box(T t) { this.t = t; } 
    public void put(T t) { this.t = t;} 
    public T take() { return t; } 
    public boolean equalTo(Box<T> other) { return this.t.equals(other.t); } 
    public Box<T> copy() { return new Box<T>(t); } 
} 

class Test { 
    public static void main(String[] args) { 
    Box<?> box = new Box<String>("abc"); 
    box.put("xyz");  // error 
    box.put(null);  // ok 

    String s = box.take(); // error 
    Object o = box.take(); // ok 

    boolean equal = box.equalTo(box); // error {confused} 
    equal = box.equalTo(new Box<String>("abc")); // error {confused} 

    Box<?> box1 = box.copy(); // ok 
    Box<String> box2 = box.copy(); // error 
    } 
} 

nie może dowiedzieć się, dlaczego poniżej dwie metody zwanej zawiedzie:

boolean equal = box.equalTo(box); 
equal = box.equalTo(new Box<String>("abc")); 

Dzięki

+4

Co mówi błąd i czego nie rozumiesz? –

+0

@SotiriosDelimanol jest po prostu pomyślałem, że parametr dla equalTo() będzie Box i nie rozumiem, dlaczego Box nie może przyjąć "box" i "new Box (" abc ")" jako argument. – foolhunger

+0

Kiedy mówisz o błędzie, masz na myśli błąd kompilatora lub błąd środowiska wykonawczego? – smac89

Odpowiedz

7
Box<?> box = new Box<String>("abc"); 
box.put("xyz");  // error 
String s = box.take(); // error 
  1. W OOP, używasz polimorfizm. Więc w czasie kompilacji, typ obiektu pola jest Box<?>

  2. Type<?> To się nazywa nieznany wieloznaczny. Ponieważ nie wiesz, do jakiego typu urządzenia jest przypisywane, możesz czytać tylko z tego obiektu i możesz używać tylko obiektów odczytanych jako instancje obiektu. Dlatego otrzymano błąd box.put("xyz") i otrzymano błąd String s = box.take().

Po drugie

boolean equal = box.equalTo(box); 

equalTo odebraniu Box<T> nie Box<?>. Jak wyjaśniłem powyżej, T oznacza każdą klasę, ale ? oznacza tylko nieznaną wieloznaczną, te dwa pojęcia nie są takie same.

I jeszcze jedna rzecz, którą powinieneś wiedzieć. W Javie ogólny jest w trakcie kompilacji. W przeciwieństwie do innych, takich jak C#, generyczny jest w czasie wykonywania.

Oto link referencyjny o zamiennika: Java wildcard

Nadzieja to pomaga :)

5

Sposób equalTo zajmuje Box<T> nie Box<?>. Gdy masz obiekt typu Box<?>, nie można ustawić parametru Box<String> ani nawet Box<?> jako parametru na equalTo, ponieważ typy obu tych pól mogą być różne.

Należy pamiętać, że kompilator użyje statycznego typu obiektu podczas kompilacji.

Tak, to nie:

Box<?> b = new Box<String>(); 
b.equalTo(new Box<String>("abc"); 

Ale to nie będzie:

Box<String> b = new Box<String>(); 
b.equalTo(new Box<String>("abc"); 
3

Nie mogę zrozumieć, dlaczego poniżej dwie metody zwanej zawiedzie

one niepowodzeniem, ponieważ jest to jak działa symbol wieloznaczny.

Symbol wieloznaczny oznacza "pewien typ, o którym już nie wiemy".

Zróbmy prostszą klasę.

Kiedy mamy Holder<?>, mamy specjalne zasady, w jaki sposób możemy uzyskać do niego dostęp. W szczególności nie możemy wywoływać metod z ogólnym argumentem. Dzieje się tak dlatego, że nie wiemy już, jaki to jest typ: mogłoby to być niebezpieczne.

Kiedy mamy Holder<?> mamy coś podobnego (koncepcyjnie):

class Holder<?> { 
    private X obj; 

    void set(X obj) { 
     this.obj = obj; 
    } 

    Object get() { 
     return obj; 
    } 
} 

Gdzie X oznacza typ jest niedostępne dla nas, bo nie wiemy, co to jest więcej.

  • get powraca Object ponieważ jest to jedyna klasa możemy być pewni obj jest
  • set nie można nazwać w ogóle

przypuszczam, że to może wydawać się dziwne, bo jeśli equalTo pierwotnie zadeklarowane jak

public boolean equalTo(Box<?> other); 

to będzie można go nazwać. Jednak wieloznacznik nie działa, po prostu zastępując T z ?.

4
  • Box<?> to "pudełko nieznane".
  • Box<? extends String> byłoby „pudełko rzeczy, które są co najmniej Strings”
  • Box<String> jest zdecydowanie „pudełko strun”.
  • Więc jeśli mamy "pudełko nieznane", i staramy się umieścić w nim typ (np. Ciąg). Kompilator nie jest pewien. To pudełko nieznane. Co jeśli w rzeczywistości akceptuje tylko liczby całkowite?
  • Czy możemy wstawić null do "pudełka nieznanego"? pewnie.
  • Co mamy "dostać()" z "pudełka nieznanego"? przynajmniej obiekt.

Biorąc pod uwagę, że

Box<?> box = new Box<String>("abc"); 

Jego prośbą o kompilator zapomnieć o <String> i zakładamy box jest "pudełko nieznany".Błędy, które widzisz, wskazują, że kompilator nie może już wpisywać sprawdzania argumentów. Nie można sprawdzić, czy dany typ należy do nieznanego, czy nie (z wyjątkiem wartości null).