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:
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.
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
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.