2015-03-27 12 views
5

Ich habe es versäumt, dieses Problem zu googlen. Warum würde diese Zeile einen Kompilierungsfehler erzeugen?Code mit Generika wird nicht kompiliert

wrapper.doSmth(wrapper.getCurrent()); 

Ich bin mit Java 7.

public class App { 
Wrapper<?> wrapper; 

class Generic<T>{ 

} 

class Wrapper<T>{ 
    Generic<T> current; 

    public void doSmth(Generic<T> generic){ 
    } 

    public Generic<T> getCurrent(){ 
    return current; 
    } 
} 

public void operation(){ 
    wrapper.doSmth(wrapper.getCurrent()); 
} 
} 

Der Fehler ist:

Error:(25, 24) java: method doSmth in class App.Wrapper<T> cannot be applied to given types; 
    required: App.Generic<capture#1 of ?> 
    found: App.Generic<capture#2 of ?> 
    reason: actual argument App.Generic<capture#2 of ?> cannot be converted to conf.App.Generic<capture#1 of ?> by method invocation conversion 
+3

Können Sie den tatsächlichen Kompilierungsfehler posten? – Waterbagel

+1

@Waterbagel Ich habe meinen Post bearbeitet, um eine Fehlermeldung zu enthalten – doctorgester

+0

Und vielleicht könnten Sie uns sagen, was dieser Code soll; Welches Problem wollen Sie lösen? – GhostCat

Antwort

8

Der Übersetzungsfehler etwas entlang der Linien von „capture sein sollten 1 # ist nicht wahr? kompatibel mit der Aufnahme von? # 2 ". Die Ursache dieses Fehlers ist, dass wrapper ein Wrapper<?> ist.

Der Compiler sieht, dass die wrapper.getCurrent() ein Generic<?> zurückkehrt, und daß wrapper.doSmth nimmt ein Generic<?> als Parameter. Aber es wird nicht die beiden ? Wildcards gleichsetzen, auch wenn wir sehen können, dass sie aus der gleichen Instanz stammen und identisch sein sollten.

Eine Lösung hier ist, die App Klasse generisch zu machen, so dass Sie den Platzhalter ersetzen können.

public class App<T> { 

Aufgrund der Tatsache, dass Generic und Wrapper innere Klassen sind, T ist noch im Rahmen, so dass Sie nicht einen generischen Typparameter für sie nicht mehr erklären müssen.

Wrapper wrapper; 

    class Generic{ 

    } 

    class Wrapper{ 
     Generic current; 

     public void doSmth(Generic generic){ 
     } 

     public Generic getCurrent(){ 
      return current; 
     } 
    } 

    public void operation(){ 
     wrapper.doSmth(wrapper.getCurrent()); 
    } 
} 
+0

"Aber es wird nicht die beiden? Wildcards gleichsetzen, auch wenn wir sehen können, dass sie aus der gleichen Instanz kommen und sollten die gleichen sein." Das war der Zweck meiner Frage. Gibt es irgendwelche Logiken dahinter? – doctorgester

+0

Das '' 'könnte zu jeder Zeit alles sein. Theoretisch könnte etwas den "Strom" durch etwas austauschen, das einen völlig anderen Typparameter hat. Vielleicht könnte etwas ein Thread sein, der diese Zuweisung während der Operation ausführt. tl; dr Zwei '' 's können nicht immer gleichwertig sein. – rgettman

+0

Nun, das war das einzige, was ich annahm. Nicht wirklich glücklich darüber. Ich danke Ihnen lieber Herr! – doctorgester

1

Könnte ein Job für eine capturing helper sein.

public void operation() { 
    operationImpl(wrapper); 
} 

private static <T> void operationImpl(Wrapper<T> wrapper) { 
    wrapper.doSmth(wrapper.getCurrent()); 
} 

Keine weitere Änderung erforderlich. Der Helfer erfasst den Typ wrapper, so dass wir sicher sein können getCurrent gibt den gleichen Typ wie doSmth akzeptiert.


Der Grund dieser Fehler passiert, ist, dass jedes Mal, wenn ein Typ mit einem Platzhalter bezeichnet wird, ein eindeutiger Typ für diesen spezifischen Punkt in dem Ausdruck angenommen wird (so genannten ‚capture‘):

Wrapper<?> wrapper = ...; 

// each capture for T is assumed distinct from each other 
// vvvvvvv  vvvvvvv 
    wrapper.doSmth(wrapper.getCurrent()); 

Die Tatsache, dass die Referenzen auf dieselbe Instanz verweisen, ist für die Art der Erfassung nicht relevant. Der Compiler ist nicht dafür zur Rechenschaft erforderlich und so etwas wie dies auch

Wrapper<?> wrapper = new Wrapper<String>(); 
wrapper.doSmth((wrapper = new Wrapper<Float>()).getCurrent()); 

passieren kann, wo T kann Mitte Ausdruck ändern.

Verwandte Themen