Ich habe ein einfaches Programm wie folgt:
%Vor%Wie Sie sehen können, tut es absolut nichts. Zusammenstellung dieser Programmdateien auf Java 1.6 und 1.7 mit folgendem Fehler:
/ D: / Projekte /.../ test / TestGenericsInheritance.java: [24,19] test.TestGenicsInheritance.B ist nicht abstrakt und überschreibt es nicht abstrakte Methode foo (java.lang.Object) in test.TestGenericsInheritance.A /D:/Projects/.../test/TestGenericsInheritance.java:[27,25] Name Konflikt: foo (T) in test.TestGenericsInheritance .B und foo (T) in test.TestGenericsInheritance.A haben die gleiche Löschung, aber auch nicht überschreibt den anderen /D:/Projects/.../test/TestGenericsInheritance.java:[26,9] Methode funktioniert überschreiben oder implementieren Sie keine Methode aus einem Supertype
Die Klassen C und B sind semantisch identisch, jedoch erkennt Klasse B die Methode foo nicht als Implementierung von A # foo. Um diesen Code kompatibel zu machen, muss ich die Methode A # foo in Klasse B mit folgender Signatur implementieren:
%Vor%Meine Frage ist, warum mein Programm nicht kompiliert? Die generischen Typen Q und T sind vollständig unabhängig, weshalb kann ich die generische Funktion A # foo nur implementieren, wenn ich explizit den generischen Typ Q für die geerbte Klasse A festlege?
Danke
B
erweitert den Rohtyp A
. Da Sie einen unformatierten Typ verwenden, werden alle generischen Informationen gelöscht, nicht nur die Typvariable, die Sie nicht angeben konnten (siehe Abschnitt 4.6 der Java-Sprachspezifikation ). Dies bedeutet, dass A
eine Methode void foo(Object obj)
hat, während A<SomeType>
eine Methode <T> void foo(T obj)
hat.
Wenn Sie eine Methode überschreiben, muss sie dieselbe Signatur haben (optional nach dem Löschen des Typs der überschriebenen Methode) - interessanterweise kann die überschreibende Methode einen anderen, spezifischeren Rückgabetyp haben. Die Signaturen der beiden Methoden sind unterschiedlich (Sie müssten in der Überschreibungsmethode Typ löschen). Daher wird Ihr Beispiel nicht kompiliert.
Das Grundtyp-Löschen wurde so implementiert, wie es ist, ist Abwärtskompatibilität. Die Idee war, dass neuer Code nur Generika verwenden würde und dass nur alter Code rohe Typen verwenden würde. Das Ziel war also nicht, rohe Typen zu den bequemsten zu machen (weil neuer Code sie ohnehin nicht verwenden sollte), sondern Rohtypen am kompatibelsten zu machen.
Betrachten wir zum Beispiel die Klasse ArrayList
, die in Java 2 eingeführt wurde (lange vor Generics). Es hatte eine Methode public Object[] toArray(Object[] a)
. In Java wurden 5 Generics eingeführt, und die Signatur dieser Methode konnte ohne Probleme in public <T> T[] toArray(T[] a)
(wobei T
nicht der Elementtyp ist) geändert werden: wegen der Art, wie Löschart implementiert wird, für alten Code, der (oder subclassed) ArrayList
und nicht ArrayList<SomeType>
die Methodensignatur blieb gleich.