Come viene scelto un metodo sovraccarico quando un parametro è il valore null letterale?

Mi sono imbattuto in questa domanda in un quiz,

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); } } 

L’output di questo programma è “String Version”. Ma non ero in grado di capire perché passare un metodo null a un metodo sovraccarico ha scelto la versione stringa. Null è una variabile stringa che punta a nulla?

Tuttavia, quando il codice è cambiato,

 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); } } 

dà un errore di compilazione dicendo “Il metodo metodo (StringBuffer) è ambiguo per il tipo MoneyCalc”

Null è una variabile stringa che punta a nulla?

Un riferimento null può essere convertito in un’espressione di qualsiasi tipo di class. Quindi, nel caso di String , questo va bene:

 String x = null; 

Il sovraccarico String qui viene scelto perché il compilatore Java sceglie il sovraccarico più specifico , come indicato nella sezione 15.12.2.5 del JLS . In particolare:

L’intuizione informale è che un metodo è più specifico di un altro se qualsiasi chiamata gestita dal primo metodo può essere passata all’altro senza un errore di tipo in fase di compilazione.

Nel secondo caso, entrambi i metodi sono ancora applicabili, ma né StringStringBuffer sono più specifici dell’altro, quindi nessuno dei due metodi è più specifico dell’altro, quindi l’errore del compilatore.

Inoltre, il JLS 3.10.7 dichiara anche che “null” è un valore letterale del “tipo nullo”. Pertanto esiste un tipo chiamato “null”.

Successivamente, JLS 4.1 afferma che esiste un tipo nullo di cui è imansible dichiarare le variabili, ma è ansible utilizzarlo solo con il valore letterale null. Più tardi dice:

Il riferimento null può sempre subire una conversione di riferimento allargata a qualsiasi tipo di riferimento.

Perché il compilatore decida di allargarlo a String potrebbe essere spiegato nella risposta di Jon .

È ansible assegnare una string a un valore null modo che sia valida e l’ordine per Java e la maggior parte dei linguaggi di programmazione sia adatto al tipo più vicino e quindi a object.

Per rispondere alla domanda nel titolo: null non è né una String né un Object , ma un riferimento a uno può essere assegnato a null .

In realtà sono sorpreso che questo codice sia compilato. Ho provato qualcosa di simile in precedenza e ho ottenuto un errore del compilatore dicendo che la chiamata era ambigua.

Tuttavia, in questo caso, sembra che il compilatore stia scegliendo il metodo più basso nella catena alimentare. Supponiamo che tu voglia la versione meno generica del metodo per aiutarti.

Dovrò vedere se riesco a trovare l’esempio in cui ho ottenuto un errore del compilatore in questo (apparentemente) stesso identico scenario, sebbene …]

EDIT: vedo. Nella versione che ho realizzato, avevo due metodi sovraccaricati che accettano una String e un Integer . In questo scenario, non esiste un parametro “più specifico” (come in Object e String ), quindi non può scegliere tra di essi, a differenza del codice.

Domanda molto bella!

Come il tipo di stringa è più specifico del tipo di object. Supponiamo che tu aggiunga un altro metodo che accetta un tipo Integer.

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

Quindi riceverai un errore del compilatore che dice che la chiamata è ambigua. Come ora abbiamo due metodi ugualmente specifici con la stessa precedenza.

Il compilatore Java fornisce la maggior parte del tipo di class derivata per assegnare null.

Ecco l’esempio per capirlo:

 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); } } 

uscita: Classe B.

d’altra parte:

 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); } } 

Risultato: il metodo fun (C) è ambiguo per il tipo MyTest

Spero che possa aiutare a capire meglio questo caso.

Direi nessuno dei due NULL è uno stato non un valore. Dai un’occhiata a questo link per maggiori informazioni su questo (l’articolo si applica a SQL, ma penso che sia d’aiuto anche con la tua domanda).