Methodenüberladung für Nullargument


133

Ich habe drei Methoden mit Parametern hinzugefügt:

public static  void doSomething(Object obj) {
    System.out.println("Object called");
}

public static  void doSomething(char[] obj) {
    System.out.println("Array called");
}

public static  void doSomething(Integer obj) {
    System.out.println("Integer called");
}

Wenn ich aufrufe doSomething(null), gibt der Compiler Fehler als mehrdeutige Methoden aus . Also ist das Problem weil Integerund char[]Methoden oder Integerund ObjectMethoden?


3
Ändern Sie einfach die Integerzu int.
Mudassir

2
@Mudassir: und was genau würde das lösen?
Joachim Sauer

2
@Joachim Sauer: Wenn von Integer zu int geändert, wird null in Java nicht auf primitive Typen bezogen, sodass der Compiler keinen Fehler auslöst.
Phani

@ Joachim Sauer: Es wird den reference to doSomething is ambiguousFehler nicht werfen .
Mudassir

Antworten:


211

Java wird immer versuchen, die spezifischste anwendbare Version einer verfügbaren Methode zu verwenden (siehe JLS §15.12.2 ).

Object, char[]Und Integeralle nehmen kann nullals gültigen Wert. Daher sind alle 3 Versionen anwendbar, sodass Java die spezifischste finden muss.

Da Objectes sich um den Supertyp von handelt char[], ist die Array-Version spezifischer als die Object-Version. Wenn also nur diese beiden Methoden existieren, wird die char[]Version ausgewählt.

Wenn sowohl die char[]als auch die IntegerVersion verfügbar sind, sind beide spezifischer als, Objectaber keine ist spezifischer als die andere, sodass Java nicht entscheiden kann, welche Version aufgerufen werden soll. In diesem Fall müssen Sie explizit angeben, welches Sie aufrufen möchten, indem Sie das Argument in den entsprechenden Typ umwandeln.

Beachten Sie, dass dieses Problem in der Praxis weitaus seltener auftritt, als man denkt. Der Grund dafür ist, dass dies nur passiert, wenn Sie explizit eine Methode mit nulloder mit einer Variablen eines eher unspezifischen Typs (z. B. Object) aufrufen .

Im Gegenteil, der folgende Aufruf wäre völlig eindeutig:

char[] x = null;
doSomething(x);

Obwohl Sie den Wert immer noch übergeben null, weiß Java genau, welche Methode aufgerufen werden muss, da der Typ der Variablen berücksichtigt wird.


1
Dies gilt für Java 7. Gilt das auch für frühere Java-Versionen? Ich meine: Wenn Sie mehrere Methodensignaturen mit Parametern nur entlang einer Typhierarchie haben, sind Sie dann auf der Speicherseite mit null als tatsächlichem Wert? Und wenn Sie eine "Hierarchie für" wie im Beispiel hier erstellt haben, sind Sie es nicht?
Christian Gosch

2
Ich bin mir ziemlich sicher, dass diese Regeln für mindestens alles seit Java 1.1 gleich sind (außer natürlich für das Hinzufügen von Generika).
Joachim Sauer

Bedeutet dies, dass doSomething (String str) aufgerufen wird, wenn der Compiler zur Laufzeit mit doSomething (null) zwischen doSomething (String str) und doSomething (Object obj) wählen soll.
Sameer

42

Jedes Paar dieser drei Methoden ist für sich mehrdeutig, wenn es mit einem nullArgument aufgerufen wird . Weil jeder Parametertyp ein Referenztyp ist.

Im Folgenden finden Sie drei Möglichkeiten, eine bestimmte Methode von Ihnen mit null aufzurufen.

doSomething( (Object) null);
doSomething( (Integer) null);
doSomething( (char[]) null);

Darf ich vorschlagen, diese Mehrdeutigkeit zu beseitigen, wenn Sie tatsächlich vorhaben, diese Methoden mit nullArgumenten aufzurufen . Ein solches Design führt in Zukunft zu Fehlern.


1
Nur Integer- char[]Paar ist mehrdeutig, da der Java-Compiler in zwei anderen Fällen die spezifischste Auswahl treffen kann, wie @JoachimSauer beschrieben.
Kajacx

1
@kajacx: ​​OPs ursprüngliche Frage war, diese Methoden mit nullals Parameter aufzurufen . Unter dieser Voraussetzung sind alle drei Paare mehrdeutig. Für den allgemeinen Fall stimme ich zu, dass nur ein Integer - char[]Paar mehrdeutig ist.
Jmg

Was ist mit doSomething(null)für public static void doSomething(String str) { System.out.println("String called"); } Dies gibt eine aufgerufene Zeichenfolge zurück.
Sameer

Ist es möglich, eine Anotation wie "nullable" oder "not nullable" zu verwenden und die Deklarationen so einzurichten, dass nur die eine Methode verwendet wird, mit der Sie eine Null erhalten möchten, sodass ein explizites "null" -Argument (jedoch impliziter Nulltyp) immer eindeutig auswählt eine bestimmte Überlastung?
Peterk

4

nullist ein gültiger Wert für einen der drei Typen; Daher kann der Compiler nicht entscheiden, welche Funktion verwendet werden soll. Verwenden Sie so etwas wie doSomething((Object)null)oder doSomething((Integer)null)stattdessen.


Ich habe die Methode mit dem Parameter Integer entfernt. Sie ruft die Funktion auf und gibt die Ausgabe als "Array Called" zurück . Wie lautet also der Vertrag zwischen Array und Object ?
Phani

2
Java-Arrays sind auch Objekte.
Zds

2

Jede Klasse in Java erweitert die Object-Klasse. Selbst die Integer-Klasse erweitert auch Object. Daher werden sowohl Object als auch Integer als Object-Instanz betrachtet. Wenn Sie also null als Parameter übergeben, wird der Compiler verwirrt, welche Objektmethode aufgerufen werden soll, dh mit dem Parameter Object oder dem Parameter Integer, da beide Objekte sind und ihre Referenz null sein kann. Die Grundelemente in Java erweitern Object jedoch nicht.


1

Ich habe dies versucht und wenn es genau ein Paar überladener Methoden gibt und eine davon einen Parametertyp Objekt hat, wählt der Compiler immer die Methode mit einem spezifischeren Typ aus. Wenn es jedoch mehr als einen bestimmten Typ gibt, gibt der Compiler einen mehrdeutigen Methodenfehler aus.

Da es sich um ein Ereignis zur Kompilierungszeit handelt, kann dies nur geschehen, wenn dieser Methode absichtlich null übergeben wird. Wenn dies absichtlich gemacht wird, ist es besser, diese Methode erneut ohne Parameter zu überladen oder eine andere Methode insgesamt zu erstellen.


0

Aufgrund von doSomething (char [] obj) und doSomething (Integer obj) besteht eine Mehrdeutigkeit.

char [] und Integer sind beide für null gleich überlegen, weshalb sie mehrdeutig sind.


0
class Sample{
  public static void main (String[] args) {
       Sample s = new Sample();
       s.printVal(null);

    } 
    public static void printVal(Object i){
        System.out.println("obj called "+i);
    }

    public static void printVal(Integer i){
        System.out.println("Int called "+i);
    }
}

Die Ausgabe heißt Int und heißt null. Die Mehrdeutigkeit besteht also aus char [] und Integer

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.