2015-01-02 19 views
7

Sto imparando Java Generics di recente, e sto solo provando ad andare con "Java Generics FAQ".Java Generics Wildcard confusione

La seguente domanda (n. 304) relativa al tipo di parametro con caratteri jolly kinda mi ha confuso, apprezzerebbe il vostro aiuto.

Esempio di codice:

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 
    } 
} 

non riesce a capire il motivo per cui qui di seguito due metodo chiamato fallirà:

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

Grazie

+4

Cosa dice l'errore e cosa non capisci a riguardo? –

+0

@SotiriosDelimanolis ha appena pensato che il parametro per equalTo() sarà Box e non capisco perché Box non possa accettare "box" e "nuova casella (" abc ")" come argomento. – foolhunger

+0

Quando dici errore, intendi errore del compilatore o errore di runtime? – smac89

risposta

7
Box<?> box = new Box<String>("abc"); 
box.put("xyz");  // error 
String s = box.take(); // error 
  1. In programmazione orientata agli oggetti, si sta utilizzando il polimorfismo . Così a tempo di compilazione, il tipo di oggetto casella è Box<?>

  2. Type<?> Questo si chiama sconosciuta jolly. Poiché non sai a che tipo di Box è stato assegnato, puoi solo leggere da quell'oggetto, e puoi solo usare gli oggetti letti come istanze di Object. Ecco perché box.put("xyz") viene ricevuto errore e String s = box.take() viene ricevuto errore.

Secondo:

boolean equal = box.equalTo(box); 

Il equalTo è ricevuto Box<T> non Box<?>. Come ho spiegato sopra, T sta per qualsiasi classe, ma ? significa solo carattere jolly sconosciuto, questi due termini non sono gli stessi.

E altro punto che dovresti sapere. In Java, generico è in fase di compilazione. Contrariamente ad altri come C#, generico è in fase di esecuzione.

Questo è il link di riferimento su jolly: Java wildcard

Spero che questo aiuto :)

5

Il metodo equalTo prende un Box<T>, non Box<?>. Se si dispone di un oggetto di tipo Box<?>, non è possibile inserire Box<String> o Box<?> come parametro su equalTo in quanto i tipi di due caselle T potrebbero non essere uguali.

Ricordare che il compilatore utilizzerà il tipo statico dell'oggetto in fase di compilazione.

Quindi, questa fallirà:

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

ma questo non sarà:

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

Non può capire perché qui di seguito due metodo chiamato mancherà

Non riescono perché questo è come funziona il jolly.

Il carattere jolly rappresenta "un tipo che non conosciamo più".

Facciamo una classe più semplice.

class Holder<T> { 
    private T obj; 

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

    T get() { 
     return obj; 
    } 
} 

Quando abbiamo un Holder<?>, abbiamo delle regole speciali per come possiamo accedervi. In particolare, non possiamo chiamare metodi con argomenti generici. Questo perché non sappiamo più quale sia il tipo: farlo sarebbe pericoloso.

quando abbiamo un Holder<?> abbiamo qualcosa di simile (concettualmente):

class Holder<?> { 
    private X obj; 

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

    Object get() { 
     return obj; 
    } 
} 

Dove X significa che il tipo è off-limits per noi, perché non sappiamo che cosa è più.

  • get rendimenti Object perché è l'unica classe che possiamo essere sicuri obj è
  • set non può essere chiamato a tutti

Suppongo che questo potrebbe sembrare strano, perché se il tuo equalTo era originariamente dichiarato come

public boolean equalTo(Box<?> other); 

quindi sarebbe in grado di chiamarlo. Tuttavia, il carattere jolly non funziona semplicemente sostituendo T con ?.

4
  • Box<?> è "una scatola di sconosciuto".
  • Box<? extends String> sarebbe "una scatola di cose che sono almeno Strings"
  • Box<String> è sicuramente "una scatola di stringhe".
  • Quindi, se abbiamo una "scatola di sconosciuto", e proviamo a mettere un tipo (ad esempio una stringa) in esso. Il compilatore non è sicuro. È una scatola di sconosciuti. E se in realtà accettasse solo gli interi?
  • Possiamo mettere un null in "scatola di sconosciuto"? sicuro.
  • Cosa dobbiamo "ottenere()" da una "scatola di sconosciuto"? almeno un oggetto.

Dato che,

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

sua chiedono compilatore per dimenticare <String> e supponiamo box è "una scatola di sconosciuto".Gli errori che vedi, indicano che il compilatore non può più eseguire il controllo dei tipi degli argomenti. Non può controllare che il dato tipo appartenga allo sconosciuto o meno (eccetto per null).