2015-12-28 19 views
6

Ich habe eine Java-Schnittstelle wie dieseBounded Typ Parameter Ausgabe Casting

public interface MyInterface<T> { 
    public <V extends T> V get(String key, Bundle bundle); 
} 

Sie bitte die <V extends T> Typparameter des Verfahrens beachten.

Dann habe ich eine Klasse MyFoo implements MyInterface

class MyFoo implements MyInterface<Object> { // Object because can be any type 

    @Override public <V> V get(String key, Bundle bundle) { 
    return new Other(); 
    } 
} 

Also, wenn ich jetzt eine Klasse wie diese:

class Bar { 
    public Other other; 

    public Other setOther(Other other); 
} 

Dann will ich MyFoo nehmen Other in einer Bar Instanz zu setzen:

MyFoo foo = new MyFoo(); 
Bar bar = new Bar(); 
bar.other = foo.get(); 

Das funktioniert perfekt. Typ kann durch Java Generics bestimmt werden. Es ist keine zusätzliche Besetzung erforderlich.

MyFoo foo = new MyFoo(); 
Bar bar = new Bar(); 
bar.setOther(foo.get()); // Fails 

Dann bekomme ich die folgende Compiler-Fehler:

error: incompatible types: Object cannot be converted to Other

Ich verstehe nicht, warum diese doesn

Wenn ich jedoch bar.setOther() dann die Art verwenden möchten, können nicht ermittelt werden Funktioniert nicht für die bar.setOther(foo.get()) Methode funktioniert aber beim direkten Zugriff auf das Feld bar.other = foo.get()

Jede Idee, wie Sie das ohne Addin zu lösen Ein zusätzlicher Cast wie bar.setOther((Other) foo.get())

Antwort

3

In einer Zuweisung weiß der Java-Compiler, welcher Rückgabetyp für die Methode verwendet werden soll, indem er sich den Typ anschaut, dem er zugewiesen ist. So Ihre Frage zu beantworten

Any idea how to solve that without adding an extra cast like bar.setOther((Other) foo.get()) ?

Dies ist ein Weg, in dem Sie das tun können:

Other value = foo.get(); 
bar.setOther(value); 

Es gibt eine andere Art und Weise ist, die schlechter aussieht, aber noch nicht eine Besetzung hat:

bar.setOther(foo.<Other>get()); 

Und eine dritte Alternative: Wechseln Sie zu Java 8; in Java 8 können Sie einfach bar.setOther(foo.get()); tun.

Für Java 7, die Regeln für diese Art Inferenz sind in JLS section 15.12.2.8 angegeben:

If any of the method's type arguments were not inferred from the types of the actual arguments, they are now inferred as follows.

If the method result occurs in a context where it will be subject to assignment conversion (§5.2) to a type S, then [...]

Verfahren Ergebnis Zuordnung Umwandlung unterworfen ist, wenn sie in einem Zuweisungsausdruck verwendet wird.

  • Otherwise, the unresolved type arguments are inferred by invoking the procedure described in this section under the assumption that the method result was assigned to a variable of type Object .

Wenn das ungelöste Typargument in einem Verfahren, dessen Ergebnis verwendet wird, nicht in einem Zuweisungsausdruck verwendet wird, dann wird das Typargument interpretiert, als ob das Verfahren Ergebnis einer Variablen des Typs Object zugewiesen wurde. Dies bedeutet in diesem Fall, dass das Rückgabetyp der get()-Methode Object ist, wenn das Ergebnis der get()-Methode keiner Variablen zugewiesen ist.

+0

Ja, das ist eine Art Workaround. Also kann der Compiler den Typparameter von 'setOther()' nicht betrachten? Klingt seltsam ... – sockeqwe

+0

@dasblinkenlight Ich werde den JLS-Abschnitt ausgraben, aber ich denke, es hat damit zu tun, dass eine Methode für viele Parameterarten überladen werden kann und die JLS die Methodenauswahl nicht überladen lassen wollte Betontypauswahl für generische Typen interferieren miteinander. –

+0

überladen Methoden ... klingt plausibel – sockeqwe