2014-10-03 7 views
5

Bitte sehen Sie diese Java-KlasseAnruf scheint zweideutig, aber läuft perfekt mit unerwartetem Ausgang

class Demo 
{ 
    public static void a(String s) 
    { 
     System.out.println("string called"); 
    } 
    public static void a(Object a) 
    { 
     System.out.println("Object called"); 
    } 
    public static void main(String...asrgs) 
    { 
     a(null); 
    } 
} 

Der Ausgang dieses Codes ist „string genannt“ aber ich bin zu verstehen, nicht in der Lage, dass, wie Compiler in der Lage, zwischen lösen Objekt und Zeichenfolge.

Darüber hinaus untersuchen dieses Codefragment

class Demo 
{ 
    public static void a(String s) 
    { 
     System.out.println("string called"); 
    } 
    public static void a(Integer n) 
    { 
     System.out.println("number called"); 
    } 
    public static void a(Object a) 
    { 
     System.out.println("Object called"); 
    } 
    public static void main(String...asrgs) 
    { 
     a(null); 
    } 
} 

Hier erhalten wir einen Fehler der Kompilierung zu zweideutigen Aufforderung (die ganz offensichtlich ist). Irgendwelche guten Erklärungen dafür?

+0

Erklärung für die erste oder die zweite? –

+1

beide, wenn möglich :) – Gagan93

Antwort

5

Die Antwort liegt in §15.12.2 des JLS:

Der zweite Schritt den Typen in dem vorherigen Schritt für das Mitglied Methoden bestimmt sucht. Dieser Schritt verwendet den Namen der Methode und der Argumentausdrücke, um nach Methoden zu suchen, die sowohl zugänglich als auch anwendbar sind, dh Deklarationen, die für die angegebenen Argumente korrekt aufgerufen werden können.

Es kann mehr als eine solche Methode geben, in diesem Fall die spezifischste wird gewählt. Der Deskriptor (Signatur plus Rückgabetyp) der spezifischsten Methode wird zur Laufzeit verwendet, um den Methodenversand durchzuführen.

(Hervorhebung von mir)

... und §15.12.2.5, die der Abschnitt oberhalb bezieht, die die Einzelheiten der Spezifität Regeln, aber auch diese handliche Zusammenfassung:

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

In Ihrem ersten Beispiel ist a(String) spezifischer als a(Object), so dass der Compiler weiß, welche eine und glücklich ist, zu verwenden. In Ihrem zweiten Beispiel sowohl a(String) und a(Integer) sind spezifischer als a(Object), aber entweder ist anwendbar auf null und sie sind in separaten Linien (String ist String > Object, Integer ist Integer > Number > Object), die Schaffung der Mehrdeutigkeit der Compiler über beschwert.

Wenn sie in der selben Linie waren, würde es keine Zweideutigkeit geben, weil es eine einzige anwendbare spezifischste Wahl geben würde. Zum Beispiel:

class Base { 
} 
class Child extends Base { 
} 
class GrandChild extends Child { 
} 
public class Example { 

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

    public static void a(Base b) { 
     System.out.println("Base"); 
    } 

    public static void a(Child b) { 
     System.out.println("Child"); 
    } 

    public static void a(GrandChild b) { 
     System.out.println("GrandChild"); 
    } 
} 

Das "GrandChild" druckt, weil während beide a(Child) und a(GrandChild) spezifischer sind als a(Object), a(GrandChild) ist spezifischer als a(Child).

Verwandte Themen