439 Stimmen

Methode hat die gleiche Löschung wie eine andere Methode des Typs

Warum ist es nicht zulässig, die folgenden zwei Methoden in derselben Klasse zu haben?

class Test{
   void add(Set<Integer> ii){}
   void add(Set<String> ss){}
}

Ich bekomme die compilation error

Die Methode add(Set) hat die gleiche Löschung add(Set) wie eine andere Methode des Typs Test.

Ich kann das zwar umgehen, aber ich habe mich gefragt, warum javac das nicht mag.

Ich kann mir vorstellen, dass die Logik dieser beiden Methoden in vielen Fällen sehr ähnlich ist und durch eine einzige Methode ersetzt werden könnte

public void add(Set<?> set){}

Methode, aber das ist nicht immer der Fall.

Dies ist besonders ärgerlich, wenn Sie zwei Personen haben möchten. constructors die diese Argumente aufnimmt, denn dann kann man nicht einfach den Namen einer der constructors .

400voto

erickson Punkte 256579

Diese Regel soll Konflikte in altem Code vermeiden, der noch rohe Typen verwendet.

Hier ist eine Illustration, warum dies nicht erlaubt war, aus der JLS. Angenommen, ich habe vor der Einführung der Generics in Java einen Code wie diesen geschrieben:

class CollectionConverter {
  List toList(Collection c) {...}
}

Sie erweitern meine Klasse, etwa so:

class Overrider extends CollectionConverter{
  List toList(Collection c) {...}
}

Nach der Einführung der Generika habe ich beschlossen, meine Bibliothek zu aktualisieren.

class CollectionConverter {
  <T> List<T> toList(Collection<T> c) {...}
}

Sie sind nicht bereit, Aktualisierungen vorzunehmen, also lassen Sie Ihre Overrider Klasse allein. Um die Klasse korrekt zu überschreiben toList() Methode haben die Sprachdesigner beschlossen, dass ein Rohtyp mit jedem generierten Typ "überschreibungsäquivalent" ist. Das bedeutet, dass Ihre Methodensignatur zwar formal nicht mehr mit der Signatur meiner Oberklasse übereinstimmt, Ihre Methode aber immer noch überschrieben wird.

Nun vergeht die Zeit und Sie beschließen, dass Sie Ihre Klasse aktualisieren möchten. Aber Sie vermasseln es ein wenig, und anstatt die bestehende, unbearbeitete toList() Methode, Sie hinzufügen. eine neue Methode wie diese:

class Overrider extends CollectionConverter {
  @Override
  List toList(Collection c) {...}
  @Override
  <T> List<T> toList(Collection<T> c) {...}
}

Aufgrund der Überschreibungsäquivalenz von Rohtypen sind beide Methoden in einer gültigen Form, um die toList(Collection<T>) Methode. Aber natürlich muss der Compiler eine einzelne Methode auflösen. Um diese Zweideutigkeit zu beseitigen, dürfen Klassen nicht mehrere Methoden haben, die gleichwertig sind, d. h. mehrere Methoden mit denselben Parametertypen nach dem Löschen.

Der Schlüssel ist, dass dies eine Sprachregel ist, die die Kompatibilität mit altem Code, der rohe Typen verwendet, aufrechterhalten soll. Es handelt sich nicht um eine Einschränkung, die durch die Löschung von Typparametern erforderlich ist; da die Methodenauflösung zur Kompilierzeit erfolgt, hätte das Hinzufügen generischer Typen zum Methodenbezeichner ausgereicht.

139voto

GaryF Punkte 23306

Die Java-Generik verwendet Typ-Löschung. Das Bit in den spitzen Klammern ( <Integer> y <String> ) wird entfernt, so dass man am Ende zwei Methoden mit identischer Signatur hat (die add(Set) die Sie im Fehler sehen). Das ist nicht erlaubt, weil die Laufzeitumgebung nicht weiß, welche für jeden Fall zu verwenden ist.

Wenn Java jemals reified generics bekommt, dann könnten Sie dies tun, aber das ist wahrscheinlich unwahrscheinlich jetzt.

51voto

bruno conde Punkte 47059

Das liegt daran, dass die Java Generics mit Typ Löschung .

Ihre Methoden würden zur Kompilierzeit in etwas wie übersetzt werden:

Die Methodenauflösung erfolgt zur Kompilierzeit und berücksichtigt keine Typparameter. ( siehe die Antwort von erickson )

void add(Set ii);
void add(Set ss);

Beide Methoden haben die gleiche Signatur ohne die Typparameter, daher der Fehler.

28voto

kgiannakakis Punkte 100768

Das Problem ist, dass Set<Integer> y Set<String> werden tatsächlich als eine Set von der JVM. Die Auswahl eines Typs für die Menge (in Ihrem Fall String oder Integer) ist nur syntaktischer Zucker, der vom Compiler verwendet wird. Die JVM kann nicht unterscheiden zwischen Set<String> y Set<Integer> .

8voto

Idrees Ashraf Punkte 1293

Definieren Sie eine einzelne Methode ohne Typ wie void add(Set ii){}

Sie können den Typ beim Aufruf der Methode nach Ihrer Wahl angeben. Sie funktioniert für alle Arten von Sets.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X