Wir haben einige Definitionen und die Verwendung von Generika in unserem Code vereinfacht. Jetzt haben wir einen interessanten Fall, nehmen Sie dieses Beispiel:
%Vor%Sehen Sie sich nun die Methode 'doSeomthingWeird () in MyWeirdClass an: Dieser Code wird mithilfe des Eclipse-JDT-Compilers korrekt kompiliert, wird jedoch bei Verwendung des Oracle-Compilers fehlschlagen. Da der JDT in der Lage ist, einen funktionierenden Bytecode zu erzeugen, bedeutet dies, dass dies auf JVM-Ebene ein gültiger Code ist, und es ist "nur" der Oracle-Compiler, der es nicht erlaubt, solche schmutzigen (!?) Zeug zu kompilieren. Wir verstehen, dass der Compiler von Oracle den Aufruf 'T obj = getMyClass ()' nicht akzeptiert. da T kein wirklich existierender Typ ist. Da wir jedoch wissen, dass das zurückgegebene Objekt A und B implementiert, warum nicht zulassen? (Der JDT-Compiler und die JVM tun das). Beachten Sie außerdem, dass der Generics-Code nur intern in privaten Methoden verwendet wird. Daher möchten wir sie nicht auf Klassenebene verfügbar machen und externen Code mit generischen Definitionen belasten, an denen wir nicht interessiert sind (außerhalb der Klasse).
Die Schulbuchlösung wird sein, um eine Schnittstelle zu schaffen AB erweitert A, B jedoch, da wir eine größere Anzahl von Schnittstellen haben, die in verschiedenen Kombinationen verwendet werden und von verschiedenen Modulen kommen, was gemeinsame Schnittstellen für alle Kombinationen signifikant erhöht Anzahl der "Dummy" -Schnittstellen und schließlich den Code weniger lesbar. In der Theorie würde es bis zu N-Permutationen von verschiedenen Wrapper-Schnittstellen erfordern, um alle Fälle abzudecken. Die "business-oriented-engineer" (andere nennen es die "lazy engineer") Lösung wäre, den Code auf diese Weise zu belassen und nur JDT zum Kompilieren des Codes zu verwenden. Edit: Es ist ein Fehler in Oracles Javac 6 und funktioniert auch auf Oracle's Javac 7
problemlosWas meinst du? Gibt es irgendwelche versteckten Gefahren durch die Annahme dieser "Strategie"?
Hinzufügung, um Diskussionen über (für mich) nicht relevante Punkte zu vermeiden: Ich frage nicht, warum der obige Code nicht mit dem Compiler von Oracle kompiliert wird. Ich kenne den Grund und möchte diese Art von Code nicht ohne einen guten Grund ändern, wenn er bei Verwendung eines anderen Compilers perfekt funktioniert. Bitte konzentrieren Sie sich auf die Definition und Verwendung (ohne Angabe eines bestimmten Typs) der Methode 'doSomethingWeird ()'. Gibt es einen guten Grund, warum wir nicht nur den JDT-Compiler verwenden sollten, der es erlaubt, diesen Code zu schreiben und zu kompilieren und die Kompilierung mit dem Compiler von Oracle zu stoppen, der den obigen Code nicht akzeptiert? (Danke für die Eingabe)
Bearbeiten : Der obige Code wird auf Oracle Javac 7, aber nicht auf Javac 6 korrekt kompiliert. Es ist ein Javac 6 Bug. Das bedeutet also, dass in unserem Code nichts falsch ist und wir es beibehalten können. Die Frage wird beantwortet, und ich werde es nach Ablauf der zwei Tage auf meine eigene Antwort als solche markieren. Danke an alle für das konstruktive Feedback.
So haben die Jungs von OpenJDK auf meine Frage geantwortet:
Diese Fehler werden durch die Tatsache verursacht, dass der JDK 6-Compiler dies nicht tut Typinferenz korrekt implementieren. Es wurde viel Mühe investiert JDK 7 Compiler, um alle diese Probleme loszuwerden (Ihr Programm kompiliert in JDK 7). Einige dieser Schlußfolgerungen sind jedoch verbesserungswürdig Quellkompatible Änderungen erfordern, weshalb wir keinen Backport durchführen können Diese Korrekturen in der JDK 6-Version.
Das heißt also für uns: Es ist absolut nichts falsch an unserem Code und wird offiziell auch von Oracle unterstützt. Wir können auch bei dieser Art von Code bleiben und Javac 7 mit target = 1.6 für unsere Maven Builds verwenden, während die Entwicklung in Eclipse garantiert, dass wir keine Java 7 APIs verwenden: D yaaahyyy !!!
In Java können Sie generische Methoden verwenden, wenn der generische Typ in Parameter oder Rückgabetyp der Methodensignatur verwendet wird. In Ihrer Beispiel-generischen doSomethingWeird
-Methode, aber nie in der Methodensignatur verwendet.
siehe folgendes Beispiel:
Dieser Code funktioniert gut.
JLS (Java Language Specification) sagt in generische Methode Teil:
%Vor% Nach diesem Zitat, wenn Sie T
in doSomethingWeird
Methodensignatur nicht verwenden, Was geben Sie den Rohtyp von T
in der Aufrufzeit an (in entryPoint
method)?
Ich habe den Code nicht überprüft (kompiliere mit beiden Compilern). Es gibt eine Menge seltsamer Dinge in der Sprachspezifikation auf einer noch grundlegenderen Ebene (überprüfen Sie die Array-Deklaration ...). Ich glaube jedoch, dass das obige Design wenig "überentwickelt" ist, und wenn ich die Notwendigkeit richtig übersetze, kann die erforderliche Funktionalität mit Factory Muster oder wenn Sie ein IoC-Framework (Spring?) Verwenden, dann kann die Methode der Nachschlagetechnik die Magie für Sie tun. Ich denke, der Code wird intuitiver und leichter zu lesen und zu pflegen sein.
Ich denke, die Ursache ist anders. Das ist nicht wahr, dass der Typ T in Zeile "T obj = getMyClass ();" ist unbekannt - aufgrund der Definition "T erweitert A & amp; B" ist seine Löschung A . Dies nennt man multiple bounds und es gilt: "Wenn eine mehrfache Grenze verwendet wird, wird der erste Typ, der in der Grenze erwähnt wird, als das Löschen der Typvariablen verwendet."
Basierend auf der Antwort von @ MJM empfehle ich Ihnen, den Code wie folgt zu aktualisieren. Dann wird sich Ihr Code nicht auf den JVM-Typ infer stützen.
%Vor% Ich würde wieder gehen, um das zu erstellen, was Sie eine "Dummy" -Schnittstelle AB
genannt haben.
Erstens finde ich es überhaupt nicht dumm. Es gibt zwei Klassen mit den gleichen allgemeinen Methodendefinitionen und an einer Stelle müssen Sie eine davon verwenden, unabhängig davon, welche es tatsächlich ist. Das ist die genaue Verwendung der Erbschaft. Die Schnittstelle AB
passt also perfekt hier. Und Generika sind hier die falsche Lösung. Generika waren niemals dazu gedacht, Vererbung zu implementieren.
Zweitens werden durch das Definieren der Schnittstelle alle Generics-Elemente in Ihrem Code entfernt und die Lesbarkeit verbessert. Tatsächlich macht das Hinzufügen einer Schnittstelle (oder Klasse) Ihren Code niemals weniger lesbar. Andernfalls wäre es besser, den gesamten Code in eine einzige Klasse zu legen.
Ihr Ansatz ist fraglich, weil die ungeprüften Umwandlungen die Sicherheit des Laufzeittyps opfern. Betrachten Sie dieses Beispiel:
%Vor%(Sie müssen das Programm möglicherweise mehrmals ausführen, um zu sehen, was den Wartungsprogrammierer verwirrt hat.)
Ja, in diesem einfachen Programm ist der Fehler ziemlich offensichtlich, aber was ist, wenn das Objekt um die Hälfte Ihres Programms herumgereicht wird, bis seine Schnittstelle verpasst wird? Wie würdest du herausfinden, woher das schlechte Objekt kam?
Wenn Sie das nicht überzeugte, was ist damit?
%Vor%Ist das Eliminieren paarer Deklarationen wirklich das wert?
Tags und Links compilation java generics