2016-07-14 22 views
4

Während der Migration unserer Codebasis von Java 1.7 zu 1.8 haben wir eine Fehlermeldung "Die Methode ... ist nicht anwendbar für die Argumente "an mehreren Codestellen, die alle dem gleichen Muster in der Generikennutzung folgen.Java 8 Generics Die Methode ... ist nicht anwendbar für die Argumente in Eclipse

Wir verwenden derzeit meistens Eclipse Mars (4.5.2) unter Windows 7, konnten aber das Verhalten auch mit Neon (4.6) bestätigen. Javac sowie ecj mit 1.7 Compliance-Level können beide unseren Code ohne einen Fehler kompilieren. Hier

ist ein Minimal, Complete, und prüfbare Beispiel:

public class ComplexInterfaceTest { 

    public static class Foo {} 

    public interface Bar { 
    void print(); 
    } 

    public static class SubFooBar extends Foo implements Bar { 
    public void print() { 
     System.out.println(this.getClass().getSimpleName()); 
    } 
    } 

    public static class FooBar<T extends Foo & Bar> { 
    public static <T extends Foo & Bar> FooBar<T> makeFooBar() { 
     return new FooBar<>(); 
    } 

    public void create(T value) { 
     value.print(); 
     return; 
    } 
    } 

    public static class Base<T extends Foo> {} 

    public static class Subclass extends Base<SubFooBar> { 
    public void doSomething(SubFooBar value) { 
//  FooBar.<SubFooBar>makeFooBar().create(value); 
     FooBar.makeFooBar().create(value); 
    } 
    } 

    public static void main(String[] args) { 
    new Subclass().doSomething(new SubFooBar()); 
    } 

} 

nun die kommentierten aus Linien in doSomething Umschaltungsverfahren macht den Code zu kompilieren, so dass wir tun eine Abhilfe haben. Immer noch die Fehlermeldung SubFooBarFoo nicht richtig scheint, wie die Klasse zu erweitern und implementiert Bar, so erfüllt sie den Vertrag von <T extends Foo & Bar>, die in <T extends Foo & Bar> FooBar<T> makeFooBar() erforderlich ist, so T tatsächlich IMO zu SubFooBar gebunden werden soll.

ich für ähnliche Fragen gesucht und gefunden diese: Differences in type inference JDK8 javac/Eclipse Luna? Type Inference Compiler Error In Eclipse with Java8 but not with Java7

Was ich mache es denken könnte ein ecj Fehler sein. Ich sah in Eclipse Bugzilla auch in diesem Kurs kann aber nichts Vergleichbares finden, sah ich diese:

  • 430686 Fest verified ist - ich ist nicht
  • 440019 hat mit skalaren Typ zu tun - nicht meins
  • 492.838, 448.793 haben mit Wildcards zu tun - nicht meins

Jetzt Eclipse Bugzilla Diskussionen voller Details über interne Funktionsweise des ecj sind, die ich nicht immer folgen kann. Was ich jedoch verstehe, ist der allgemeine Konsens, dass Eclipse Compiler JLS und nicht javac streng folgen muss (in Fällen, in denen es falsch war), also muss es nicht unbedingt ein Fehler in ecj sein. Wenn es kein ecj Bug wäre, dann muss der Code ein javac Bug sein.

Was ich interessiert ist - für diejenigen, die den Typ-Inferenz-Prozess meines Code-Snippets analysieren können - sollte der Code kompiliert haben oder habe ich Fehler bei der Codierung gemacht?

EDIT

Wie ich Bugzilla das Ergebnis meines Berichts Eclipse zu schreiben versprochen: der Mangel hat die ID # 497905 (Stephan Herrmann den Link in seinem Kommentar unter der akzeptierten Antwort geschrieben hat) und ist derzeit Ziel für v4.7.

+1

Ich habe gerade einen Fehlerbericht auf Eclipse Bugzilla, wird hier ihre Antworten veröffentlichen. –

Antwort

2

Bei dem Verfahren

public void doSomething(SubFooBar value) { 
    FooBar.makeFooBar().create(value); 
} 

der Typparameter T des Verfahrens makeFooBar() wird nie so SubFooBar geschlossen werden.Die Tatsache, dass Sie danach eine Instanz SubFooBar an die Methode create übergeben, hat keinen Einfluss auf den Typ des vorhergehenden Aufrufausdrucks FooBar.makeFooBar().

Dies ändert sich nicht mit der Zieleingabe von Java 8, da diese neue Funktion nicht für den Empfängerausdruck eines verketteten Methodenaufrufs verwendet werden kann.

So in allen Versionen der Typ für T des makeFooBar() Aufruf gefolgert wird der Schnitttyp Foo & Bar, so dass der Ergebnistyp ist seine FooBar<Foo&Bar>. Dies bezieht Eclipse auch ein, auch wenn der Tooltip im Editor etwas anderes anzeigt.

Dies bedeutet, dass Sie eine SubFooBar Instanz an die create Methode übergeben kann als FooBar<Foo&Bar>.create(…) eine Instanz von Foo&Bar und SubFooBarFoo erstreckt erwartet und Umsetzung Bar kompatibel ist.

Es ist möglich, zu zeigen, dass Eclipse-die gleiche Art wie alle anderen Compiler tut schließen, als eine geeignete Art Einfügen gegossen

public void doSomething(SubFooBar value) { 
    FooBar.makeFooBar().create((Foo&Bar)value); 
} 

die weg Compiler-Fehler gehen macht. Das Problem hier ist also nicht die Typinferenz, aber diese Eclipse-Version denkt, dass SubFooBar nicht zu Foo & Bar zuweisbar ist.

+2

yep, das passt auch zu meiner Analyse (https://bugs.eclipse.org/bugs/show_bug.cgi?id=497905#c1) –

+0

Also im Grunde sollte T 'Foo & Bar' sein und SubFooBar ist' Foo & Bar' der Code hätte kompilieren sollen. Gut zu wissen, danke! –

+1

Ich habe es mir etwas Zeit gelassen - ich denke, es gibt nicht viel, was hinzugefügt werden kann: Obwohl ich den richtigen Grund verpasste, ist mein Code korrekt, also wird das Problem auf die Eclipse gerichtet sein 'Version 4.7. –