web-dev-qa-db-fra.com

Comment une méthode surchargée est-elle choisie lorsqu'un paramètre est la valeur NULL littérale?

Je suis tombé sur cette question dans 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);
   }
}

Le résultat de ce programme est "String Version". Mais je n'ai pas pu comprendre pourquoi le passage d'une valeur null à une méthode surchargée a choisi la version chaîne. Est-ce que null est une variable String pointant vers rien?

Cependant, lorsque le code est changé en,

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

cela donne une erreur de compilation en disant "La méthode method (StringBuffer) est ambiguë pour le type MoneyCalc"

96
zakSyed

Est-ce que null est une variable String pointant vers rien?

Une référence null peut être convertie en une expression de tout type de classe. Donc, dans le cas de String, c'est très bien:

String x = null;

La surcharge String ici est choisie parce que le compilateur Java sélectionne la surcharge la plus spécifique, comme indiqué dans la section Section 15.12.2.5 de JLS . En particulier:

L'intuition informelle est qu'une méthode est plus spécifique qu'une autre si une invocation gérée par la première méthode peut être transmise à l'autre sans erreur de type à la compilation.

Dans votre deuxième cas, les deux méthodes sont toujours applicables, mais ni String ni StringBuffer ne sont plus spécifiques que les autres, donc aucune méthode n'est plus spécifique que l'autre, d'où l'erreur du compilateur.

101
Jon Skeet

De plus, JLS 3.10.7 déclare également que "null" est une valeur littérale du "type null". Il existe donc un type appelé "null".

Plus tard, JLS 4.1 indique qu'il existe un type null dont la déclaration de variables est impossible, mais que vous ne pouvez l'utiliser que par le littéral null. Plus tard, il est écrit:

La référence null peut toujours subir une conversion de référence élargie à n'importe quel type de référence.

Pourquoi le compilateur choisit de l'élargir à String pourrait bien être expliqué dans la réponse de Jon .

9
Edwin Dalorzo

Vous pouvez affecter une valeur string à une valeur null afin qu'elle soit valide et que l'ordre de Java et de la plupart des langages de programmation s'adapte au type le plus proche, puis à l'objet. 

2
JonH

Pour répondre à la question dans le titre: null n'est ni une String ni une Object, mais une référence à l'une ou l'autre peut être affectée à null.

Je suis même surpris que ce code soit compilé. J'ai déjà essayé quelque chose de similaire auparavant et j'ai eu une erreur de compilation qui disait que l'appel était ambigu.

Cependant, dans ce cas, il semble que le compilateur choisisse la méthode la plus basse de la chaîne alimentaire. En supposant que vous souhaitiez la version la moins générique de la méthode afin de vous aider.

Je vais devoir voir si je peux Déterrer l'exemple où j'ai eu une erreur de compilation dans ce (apparemment) exactement le même scénario, cependant ...]

EDIT: je vois. Dans la version que j'ai créée, deux méthodes surchargées acceptaient une String et une Integer. Dans ce scénario, il n'y a pas de paramètre "plus spécifique" (comme dans Object et String), il ne peut donc pas choisir entre eux, contrairement à votre code.

Très bonne question!

2
asteri

Source: https://docs.Oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12.2.5
Concept: Méthode la plus spécifique
Explication: Si plusieurs méthodes membres sont à la fois accessibles et applicables à une invocation de méthode, vous devez en choisir une pour fournir le descripteur de la répartition de la méthode d'exécution. Le langage de programmation Java utilise la règle selon laquelle la méthode la plus spécifique est choisie. Essayez de transtyper le null sur un type spécifique et la méthode que vous souhaitez sera automatiquement appelée.

0
M.P

Le type As String est plus spécifique que le type Object. Supposons que vous ajoutiez une autre méthode prenant un type Integer.

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

Ensuite, vous obtiendrez une erreur du compilateur disant que l'appel est ambigu. Comme maintenant, nous avons deux méthodes également spécifiques avec la même priorité.

0
BSingh

Le compilateur Java donne le type de classe le plus dérivé à assigner null.

Voici l'exemple pour le comprendre:

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

sortie: Classe B.

d'autre part:

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

Résultat: La méthode fun (C) est ambiguë pour le type MyTest

J'espère que cela vous aidera à mieux comprendre ce cas.

0
Ravi