2015-06-18 10 views
7

sto ottenendo l'errore sotto:Perché questa chiamata al metodo fallisce? (Generics e jolly)

'call(ContainsMonitor)' cannot invoke 'call(? extends webscout.Monitor)' in 'WebScoutCallable' 

Monitor.java

WebScoutCallable<? extends Monitor> handler; 

public setCallable(WebScoutCallable<? extends Monitor> callable) { 
    this.handler = callable; 
} 

WebScoutCallable.java

public interface WebScoutCallable<T extends Monitor> { 
    public void call(T caller); 
} 

ContainsMonitor.java

public class ContainsMonitor extends Monitor { 
    public void handleDocument() { 
      handler.call(this); 
    } 
} 

Ammetto liberamente che sono nuovo per i generici e ancora piuttosto nuovo per Java. Trovo il messaggio di errore confuso visto che dovrebbe funzionare (la dichiarazione del metodo prevede un monitor o una sottoclasse, sto passando in una sottoclasse). Qualsiasi aiuto (+ spiegazione) sarebbe molto apprezzato!

Grazie!

risposta

6

Hai un carattere jolly nel parametro di tipo della variabile handler. Il compilatore non sa quale sia esattamente il tipo di parametro di questo tipo, solo che sia Monitor o una sottoclasse.

Il metodo call prende uno T, che corrisponde al carattere jolly. Ma non vi è alcuna garanzia che il tipo di caratteri jolly sia un ContainsMonitor. Potrebbe essere un Monitor o potrebbe essere MonitorSubtypeThatDoesntExistYet. Poiché il compilatore non conosce il tipo effettivo, non può permetterti di passare nulla eccetto null, perché con qualsiasi argomento non- null, non può garantire la sicurezza del tipo.

È possibile aggirare questo rimuovendo il carattere jolly e sostituendo tale concetto con un parametro di tipo sulla classe Monitor.

class Monitor<T extends Monitor<T>> 
{ 
    WebScoutCallable<T> handler; 

    public void setCallable(WebScoutCallable<T> callable) { 
     this.handler = callable; 
    } 
} 

L'interfaccia WebScoutCallable cambia un po 'in risposta:

interface WebScoutCallable<T extends Monitor<T>> { 
    public void call(T caller); 
} 

La sottoclasse alimenta il proprio nome come argomento di tipo quando si estende Monitor.

class ContainsMonitor extends Monitor<ContainsMonitor> { 
    public void handleDocument() { 
      handler.call(this); 
    } 
} 

Ora, T sarà un tipo noto, e ContainsMonitor definisce di essere se stesso, quindi è ora legale che passasse stesso per call.

+0

Grazie per la risposta dettagliata. Ho pensato che ci potrebbe essere una soluzione meno verbosa, ma questo ha senso! – RNGuy

3

? extends Monitor significa: una sottoclasse specifica di Monitor, ma non sappiamo quale. Quindi potrebbe essere un ContainsMonitor o no e handler potrebbe o potrebbe non essere in grado di accettare un ContainsMonitor. Il compilatore non può decidere e mostra un errore.

Un modo per risolvere il tuo problema è quello di utilizzare tipi specifici, ad esempio:

class Monitor<T extends Monitor<T>> { 
    WebScoutCallable<T> handler; 

    public setCallable(WebScoutCallable<T> callable) { 
    this.handler = callable; 
    } 
} 

class ContainsMonitor extends Monitor<ContainsMonitor> { 
    public void handleDocument() { 
    handler.call(this); 
    } 
} 
+0

Grazie per la risposta rapida. Vorrei poter contrassegnare due soluzioni come corrette! – RNGuy

-5

Il codice non richiede generici.

public class Monitor { 
    WebScoutCallable handler; 

    public void setCallable(WebScoutCallable callable) { 
     this.handler = callable; 
    } 
} 

public interface WebScoutCallable { 
    public void call(Monitor caller); 
} 

public class ContainsMonitor extends Monitor { 
    public void handleDocument() { 
      handler.call(this); 
    } 
} 
+3

Questo non risponde alla domanda dell'OP –

Problemi correlati