web-dev-qa-db-de.com

Wie wird eine überladene Methode gewählt, wenn ein Parameter der literale Nullwert ist?

Ich bin in einem Quiz auf diese Frage gestoßen.

public class MoneyCalc {

   public void method(Object o) {
      System.out.println("Object Verion");
   }

   public void method(String s) {
      System.out.println("String Version");
   }

   public static void main(String args[]) {
      MoneyCalc question = new MoneyCalc();
      question.method(null);
   }
}

Die Ausgabe dieses Programms ist "String Version". Ich konnte jedoch nicht verstehen, warum die Übergabe einer Null an eine überladene Methode die Zeichenfolgenversion auswählte. Zeigt null eine String-Variable auf nichts?

Wenn jedoch der Code geändert wird,

public class MoneyCalc {

   public void method(StringBuffer sb) {
      System.out.println("StringBuffer Verion");
   }

   public void method(String s) {
      System.out.println("String Version");
   }

   public static void main(String args[]) {
      MoneyCalc question = new MoneyCalc();
      question.method(null);
   }
}

es gibt einen Kompilierungsfehler, der besagt "Die Methodenmethode (StringBuffer) ist für den Typ MoneyCalc mehrdeutig"

96
zakSyed

Zeigt null eine String-Variable auf nichts?

Eine Nullreferenz kann in einen Ausdruck eines beliebigen Klassentyps konvertiert werden. Im Fall von String ist dies in Ordnung:

String x = null;

Die String-Überladung wird hier ausgewählt, da der Java-Compiler die most Specific -Überladung gemäß Abschnitt 15.12.2.5 der JLS auswählt. Im Speziellen:

Die informelle Intuition besagt, dass eine Methode spezifischer ist als eine andere, wenn ein Aufruf, der von der ersten Methode verarbeitet wird, an die andere Methode ohne Kompilierungsfehler weitergegeben werden kann.

In Ihrem zweiten Fall sind beide Methoden noch anwendbar, aber weder String noch StringBuffer sind spezifischer als die anderen. Daher ist keine der beiden Methoden spezifischer als die andere, daher der Compiler-Fehler.

101
Jon Skeet

Darüber hinaus erklärt JLS 3.10.7 , dass "null" ein Literalwert des Typs "null" ist. Daher gibt es einen Typ namens "null".

Später erklärt JLS 4.1 , dass es einen Nulltyp gibt, dessen Variablen nicht deklariert werden können. Sie können ihn jedoch nur über das Null-Literal verwenden. Später heißt es:

Die Nullreferenz kann immer einer sich erweiternden Referenzkonvertierung unterzogen werden zu jedem Referenztyp.

Warum sich der Compiler für die Erweiterung auf String entscheidet, ist möglicherweise in Jons Antwort zu erklären.

9
Edwin Dalorzo

Sie können eine string einem null-Wert zuweisen, damit dieser gültig ist und die Reihenfolge für Java und die meisten Programmiersprachen auf den nächstgelegenen Typ und dann auf das Objekt passt. 

2
JonH

Um die Frage im Titel zu beantworten: null ist weder eine String noch eine Object, jedoch kann null ein Verweis auf beide zugewiesen werden.

Ich bin eigentlich überrascht, dass dieser Code sogar kompiliert wird. Ich habe zuvor etwas Ähnliches ausprobiert und einen Compiler-Fehler erhalten, der besagt, dass der Aufruf mehrdeutig war.

In diesem Fall scheint es jedoch so, als würde der Compiler die Methode wählen, die in der Nahrungskette am niedrigsten ist. Es wird davon ausgegangen, dass Sie die am wenigsten generische Version der Methode benötigen, um Ihnen zu helfen.

Ich muss nachsehen, ob ich das Beispiel herausfinden kann, bei dem in diesem (scheinbar) exakt gleichen Szenario ein Compiler-Fehler aufgetreten ist ...]

EDIT: Ich verstehe. In der von mir erstellten Version hatte ich zwei überladene Methoden, die eine String und eine Integer akzeptierten. In diesem Szenario gibt es keinen "spezifischsten" Parameter (wie in Object und String), so dass er anders als in Ihrem Code nicht zwischen ihnen wählen kann.

Sehr coole Frage!

2
asteri

Quelle: https://docs.Oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12.2.5
Konzept: Spezifischste Methode
Erläuterung: Wenn mehr als eine Membermethode für einen Methodenaufruf verfügbar und anwendbar ist, muss eine Methode ausgewählt werden, um den Deskriptor für den Laufzeitmethodenversand bereitzustellen. Die Programmiersprache Java verwendet die Regel, dass die spezifischste Methode ausgewählt wird. Versuchen Sie, die Null auf einen bestimmten Typ zu setzen, und die gewünschte Methode wird automatisch aufgerufen.

0
M.P

Der String-Typ ist spezifischer als der Objekttyp. Nehmen wir an, Sie fügen eine weitere Methode hinzu, die einen Integer-Typ annimmt.

public void method(Integer i) {
      System.out.println("Integer Version");
   }

Sie erhalten dann einen Compiler-Fehler, der besagt, dass der Aufruf mehrdeutig ist. Wie jetzt haben wir zwei gleich spezifische Methoden mit gleichem Vorrang.

0
BSingh

Der Java-Compiler gibt den meisten abgeleiteten Klassentyp zum Zuweisen von Null an.

Hier ist das Beispiel, um es zu verstehen:

class A{

    public void methodA(){
        System.out.println("Hello methodA");
    }
}

class B extends A{
    public void methodB(){
        System.out.println("Hello methodB");
    }
}

class C{
    public void methodC(){
        System.out.println("Hello methodC");
    }
}

public class MyTest {

     public static void fun(B Obj){
         System.out.println("B Class.");
     }
     public static void fun(A Obj){
         System.out.println("A Class.");
     }

    public static void main(String[] args) {
        fun(null);
    }
}

Ausgabe: B-Klasse.

auf der anderen Seite:

public class MyTest {

     public static void fun(C Obj){
         System.out.println("B Class.");
     }
     public static void fun(A Obj){
         System.out.println("A Class.");
     }

    public static void main(String[] args) {
        fun(null);
    }
}

Ergebnis: Die Methode fun (C) ist für den Typ MyTest mehrdeutig

Ich hoffe, es hilft, diesen Fall besser zu verstehen.

0
Ravi