ProgrammierungBackend-Entwickler

Erklären Sie, wie die Methode der Auflösungsreihenfolge von Überladungen (method resolution order) bei Vererbung in Java funktioniert und welche Fallstricke auftreten können.

Bestehen Sie Vorstellungsgespräche mit dem Hintsage-KI-Assistenten

Antwort.

In Java erfolgt die Auflösung von Überladungen (overloading) und Überschreibungen (overriding) von Methoden nach bestimmten Regeln. Bei Überladungen wählt der Compiler die am besten geeignete Methode unter allen Versionen zur Kompilierzeit aus, basierend auf dem Typ der Argumente an der Stelle des Aufrufs.

Wichtige Punkte:

  • Bei Vorhandensein von überladenen Methoden in allen Klassen und Superklassen werden zuerst die höchsten möglichen Übereinstimmungen in der aktuellen Klasse gesucht, gefolgt von den Superklassen.
  • Die Auswahl der Methode erfolgt zur Kompilierzeit und nicht zur Laufzeit.
  • Typumwandlungen (widening, autoboxing, varargs) werden bei Bedarf angewendet.

Beispiel:

class Super { void print(Number n) { System.out.println("Super Number"); } } class Sub extends Super { void print(Integer i) { System.out.println("Sub Integer"); } } ... Sub s = new Sub(); s.print(5); // Sub Integer s.print(5.0); // Super Number

Hier wird print(Integer) für das Argument des Typs Integer aufgerufen, und für den Typ Double wird die Elternmethode verwendet.

Fangfrage.

Wenn im Nachkommen eine Methode überschrieben (override) und überladen (overload) wurde, welche wird dann bei Polymorphismus aufgerufen?

Antwort: Bei Polymorphismus wird immer die Version der Methode basierend auf dem tatsächlichen Objekttyp für überschreibende Methoden (overriding) ausgewählt. Für überladene Methoden erfolgt die Auswahl zur Kompilierzeit basierend auf dem Referenztyp.

class A { void test(Number n) { System.out.println("A:Number"); } } class B extends A { void test(Integer n) { System.out.println("B:Integer"); } @Override void test(Number n) { System.out.println("B:Number"); } } ... A obj = new B(); obj.test(1); // Ruft B:Number auf, obwohl test(Integer) existiert

Beispiele für reale Fehler aufgrund der Unkenntnis der Feinheiten des Themas.


Geschichte

Ein Entwickler fügte im Unterklasse eine überladene Version der Methode hinzu und erwartete, dass sie für alle Nachfolger aufgerufen wird. In der Produktion stellte sich heraus, dass der Aufruf über die Referenz der Elternklasse zur Auswahl der Methode nach Referenztyp führte und nicht nach Objekttyp. Infolgedessen wurde die erforderliche Logik nicht ausgeführt.


Geschichte

In einem großen Projekt wurde versehentlich die Methode equals(Object) mit der Signatur equals(MyClass obj) überladen, in der Annahme, dass sie das Standard-equals ersetzen würde. Bei Vergleichen in HashSet-Sammlungen wurde das Standard-equals(Object) verwendet, was zu logischen Inkonsistenzen und Datenverlusten führte.


Geschichte

Bei der Hinzufügung einer neuen Version der Methode mit varargs in die Klassenhierarchie schien es, dass die benötigte Version für Arrays aufgerufen würde. jedoch wählte der Compiler bei der expliziten Übergabe eines Arrays nicht die richtige Überladung, was zu falscher Verarbeitung führte und der Fehler lange unentdeckt blieb.