2015-06-18 4 views
7

Ich erhalte die folgenden Fehler:Warum schlägt dieser Methodenaufruf fehl? (Generics & Wildcards)

'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); 
    } 
} 

Ich gebe frei zu, dass ich neu in Generika bin und immer noch ziemlich neu in Java bin. Ich finde die Fehlermeldung verwirrend, wie es aussieht, sollte es funktionieren (Methodendeklaration erwartet einen Monitor oder eine Unterklasse, ich übergebe in einer Unterklasse). Jede Hilfe (+ Erklärung) würde sehr geschätzt werden!

Danke!

Antwort

6

Sie einen Platzhalter in den Typ-Parametern Ihrer handler Variable hat. Der Compiler weiß nicht, was der genaue Typ dieses Typparameters ist, nur dass er entweder Monitor oder eine Unterklasse ist.

Die Methode call verwendet eine T, die auf den Platzhalter abgestimmt ist. Aber es gibt keine Garantie, dass der Platzhalter ein ContainsMonitor ist. Es könnte ein Monitor sein, oder es könnte MonitorSubtypeThatDoesntExistYet sein. Da der Compiler den tatsächlichen Typ nicht kennt, kann er Ihnen nicht erlauben, irgendetwas außer null zu übergeben, denn mit keinem Argument kann er die Typsicherheit garantieren.

Sie können dies umgehen, indem Sie den Platzhalter entfernen und dieses Konzept durch einen Typparameter der Klasse Monitor ersetzen.

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

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

Die Schnittstelle WebScoutCallable ändert sich ein wenig in der Antwort:

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

Die Unterklasse ihren eigenen Namen als Argument Typ-Feeds, wenn Monitor erstreckt.

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

Nun T wird ein bekannter Typ sein und ContainsMonitor definiert sie selbst zu sein, es ist so jetzt legal für sie selbst zu call passieren zu.

+0

Vielen Dank für die ausführliche Antwort. Ich dachte, es könnte eine weniger ausführliche Lösung geben, aber das macht Sinn! – RNGuy

3

? extends Monitor bedeutet: eine bestimmte Unterklasse von Monitor, aber wir wissen nicht welche. So kann es ein ContainsMonitor oder nicht sein und handler kann oder kann nicht ContainsMonitor akzeptieren. Der Compiler kann nicht entscheiden und zeigt einen Fehler an.

Ein Weg, um Ihr Problem zu lösen, ist bestimmte Arten zu verwenden, zum Beispiel:

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

Danke für die schnelle Antwort. Ich wünschte, ich könnte zwei Lösungen als richtig markieren! – RNGuy

-5

Ihr Code benötigt keine Generika.

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

Dies beantwortet die Frage von OP nicht –