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


98

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

La sortie de ce programme est "String Version". Mais je n'ai pas pu comprendre pourquoi passer un null à une méthode surchargée a choisi la version chaîne. Null est-il 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);
   }
}

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


Vous pouvez attribuer une chaîne à une valeur nulle pour qu'elle soit valide et que l'ordre de java et de la plupart des langages de programmation soit adapté au type le plus proche, puis à l'objet.
JonH


6
Apparemment, cela a été fermé en double par des personnes qui ne lisent que le titre. La vraie question ici est de savoir pourquoi une surcharge spécifique a été choisie, et non "ce qui est nul".
entre

Réponses:


102

Null est-il une variable String pointant vers rien?

Une référence nulle peut être convertie en une expression de n'importe quel type de classe. Donc, dans le cas de String, c'est bien:

String x = null;

La Stringsurcharge ici est choisie parce que le compilateur Java sélectionne la surcharge la plus spécifique , conformément à la section 15.12.2.5 du 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 Stringni StringBuffern'est plus spécifique que l'autre, donc aucune méthode n'est plus spécifique que l'autre, d'où l'erreur du compilateur.


3
Et en quoi la surcharge String est-elle plus spécifique que la surcharge Object?
user1610015

12
Parce qu'un Objectpeut prendre n'importe quel type et l'envelopper dans un Object, alors qu'un Stringne peut prendre qu'un String. Dans ce cas, Stringest plus spécifique d'un type par rapport au Objecttype.
JonH

10
@zakSyed Si on vous demandait ce qui est plus spécialisé "String" ou "Object", que diriez-vous? Evidemment "String", non? Si on vous demandait: qu'est-ce qui est plus spécialisé "String" ou "StringBuffer"? Il n'y a pas de réponse, ce sont deux spécialisations orthogonales, comment choisir entre elles? Ensuite, vous devez être explicite sur celui que vous voulez (c'est-à-dire en jetant votre référence nulle question.method((String)null))
Edwin Dalorzo

1
@JonSkeet: Cela a du sens. Donc, fondamentalement, il recherche une méthode selon la règle la plus spécifique et s'il n'est pas capable de décider laquelle est la plus spécifique, il générerait une erreur de compilation.
zakSyed

3
@JonH "null" est de type référence, si l'une des méthodes reçoit un type primitif comme paramètre (ie int) il ne sera même pas pris en compte par le compilateur lors du choix de la bonne méthode à invoquer pour une référence de type null. Il est déroutant si par "Int" vous vouliez dire java.lang.Integer ou si vous vouliez dire le type primitif int.
Edwin Dalorzo

9

En outre, le JLS 3.10.7 déclare également que "null" est une valeur littérale du "type nul". Il existe donc un type appelé "nul".

Plus tard, le JLS 4.1 indique qu'il existe un type nul dont il est impossible de déclarer des variables, mais vous pouvez l'utiliser uniquement via le littéral nul. Plus tard, il dit:

La référence nulle peut toujours subir une conversion de référence élargie vers 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 .


Je suis sûr que ce type est nul.
xavierm02

2
@ xavierm02 Il n'y en a aucune mention dans la spécification du langage Java. Pouvez-vous citer votre référence afin que nous puissions tous vérifier votre réclamation?
Edwin Dalorzo

Je n'ai jamais lu cette chose. Mais j'ai fait un peu de Java cet été et vous pouvez surcharger une méthode prenant un objet avec une méthode prenant un objet Void.
xavierm02

C'est plus une classe qu'un type.
xavierm02

4
@ xavierm02 Bien sûr que vous le pouvez. Vous pouvez surcharger une méthode en Java avec n'importe quel autre type de votre choix. Cela n’a cependant rien à voir avec la question ou ma réponse.
Edwin Dalorzo

2

Vous pouvez attribuer a stringà une nullvaleur pour qu'elle soit valide et que l'ordre de java et de la plupart des langages de programmation corresponde au type le plus proche, puis à l'objet.


2

Pour répondre à la question du titre: nulln'est ni un Stringni un Object, mais une référence à l'un ou l'autre peut être attribuée à null.

Je suis en fait surpris que ce code se compile même. J'ai essayé quelque chose de similaire précédemment et j'ai eu une erreur de compilation disant 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. Cela suppose que vous souhaitiez la version la moins générique de la méthode pour vous aider.

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

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

Question très cool!


null n'est ni l'un ni l'autre, mais il peut être attribué aux deux, c'est la différence et il compilera pourquoi pas - c'est du code absolument valide.
JonH

0

Le type String est plus spécifique que le type Object. Disons que vous ajoutez une autre méthode qui prend un type Integer.

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

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


0

Le compilateur Java donne le type de classe le plus dérivé à affecter 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 aidera à mieux comprendre ce cas.


0

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 plus d'une méthode membre est à la fois accessible et applicable à un appel de méthode, il est nécessaire d'en choisir un pour fournir le descripteur pour la distribution de 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 convertir la valeur null sur un type spécifique et la méthode que vous souhaitez sera automatiquement appelée.


Dans le premier exemple, String étend Object, donc "la plus spécifique" est la méthode prenant String, mais dans le second exemple, String et StringBuffer étendent tous deux Object, ils sont donc également spécifiques et le compilateur ne peut donc pas faire de choix
David Kerr

-1

Je ne dirais ni l'un ni l'autre. NULL est un état et non une valeur. Consultez ce lien pour plus d'informations à ce sujet (l'article s'applique à SQL, mais je pense que cela aide également à répondre à votre question).


nullest très certainement une valeur, telle que définie dans le JLS.
Sotirios Delimanolis
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.