Surcharge de méthode pour l'argument nul

133

J'ai ajouté trois méthodes avec des paramètres:

public static  void doSomething(Object obj) {
    System.out.println("Object called");
}

public static  void doSomething(char[] obj) {
    System.out.println("Array called");
}

public static  void doSomething(Integer obj) {
    System.out.println("Integer called");
}

Lorsque j'appelle doSomething(null), le compilateur renvoie une erreur en tant que méthodes ambiguës . Il en est de la question parce que Integeret les char[]méthodes ou Integeret Objectméthodes?

Phani
la source
3
Changez simplement le Integeren int.
Mudassir
2
@Mudassir: et qu'est-ce que cela résoudrait exactement?
Joachim Sauer
2
@Joachim Sauer: S'il est changé de Integer en int, alors null n'est pas référencé aux types primitifs en Java, donc le compilateur ne lèvera pas d'erreur.
Phani
@Joachim Sauer: Cela ne lèvera pas l' reference to doSomething is ambiguouserreur.
Mudassir

Réponses:

211

Java essaiera toujours d'utiliser la version applicable la plus spécifique d'une méthode disponible (voir JLS §15.12.2 ).

Object, char[]et Integerpeuvent tous prendre nullcomme valeur valide. Par conséquent, les 3 versions sont applicables, Java devra donc trouver la plus spécifique.

Puisqu'il Objects'agit du super-type de char[], la version du tableau est plus spécifique que la Object-version. Donc, si seulement ces deux méthodes existent, la char[]version sera choisie.

Lorsque les versions char[]et Integersont disponibles, les deux sont plus spécifiques, Objectmais aucune n'est plus spécifique que l'autre, de sorte que Java ne peut pas décider laquelle appeler. Dans ce cas, vous devrez mentionner explicitement celui que vous souhaitez appeler en convertissant l'argument dans le type approprié.

Notez qu'en pratique, ce problème se produit beaucoup plus rarement qu'on ne le pense. La raison en est que cela ne se produit que lorsque vous appelez explicitement une méthode avec nullou avec une variable d'un type plutôt non spécifique (comme Object).

Au contraire, l'invocation suivante serait parfaitement claire:

char[] x = null;
doSomething(x);

Bien que vous passiez toujours la valeur null, Java sait exactement quelle méthode appeler, car elle prendra en compte le type de variable.

Joachim Sauer
la source
1
Ceci est indiqué pour Java 7. Cela s'applique-t-il également aux versions précédentes de Java? Je veux dire: si vous avez plusieurs signatures de méthode avec des paramètres uniquement le long d'une hiérarchie de types, que vous êtes du côté de l'enregistrement avec null comme valeur réelle? Et si vous avez construit une «hiérarchie pour» comme dans l'exemple ici, alors vous ne l'êtes pas?
Christian Gosch
2
Je suis presque sûr que ces règles sont les mêmes pour au moins tout depuis Java 1.1 (sauf pour l'ajout de génériques, évidemment).
Joachim Sauer
Cela signifie-t-il que si le compilateur devait choisir entre doSomething (String str) et doSomething (Object obj) pendant l'exécution avec doSomething (null), doSomething (String str) sera appelé.
Sameer
43

Chaque paire de ces trois méthodes est ambiguë en soi lorsqu'elle est appelée avec un nullargument. Parce que chaque type de paramètre est un type de référence.

Voici les trois façons d'appeler une de vos méthodes spécifiques avec null.

doSomething( (Object) null);
doSomething( (Integer) null);
doSomething( (char[]) null);

Puis-je suggérer de supprimer cette ambiguïté si vous envisagez d'appeler ces méthodes avec des nullarguments. Une telle conception invite à des erreurs dans le futur.

jmg
la source
1
Only Integer- char[]pair est ambigu, car dans deux autres cas, le compilateur Java peut choisir le choix le plus spécifique, comme @JoachimSauer décrit.
kajacx
1
@kajacx: ​​La question originale des OP portait sur l'appel de ces méthodes avec nullcomme paramètre. Sous cette condition préalable, les trois paires sont ambiguës. Pour le cas général, je conviens que seule la Integer - char[]paire est ambiguë.
jmg
que diriez-vous doSomething(null)de public static void doSomething(String str) { System.out.println("String called"); } Cela retournera la chaîne appelée.
Sameer
Est-il possible d'utiliser une anotation comme "nullable" ou "non nullable" et configurer les déclarations de sorte que seule la méthode avec laquelle vous voulez obtenir un null afin qu'un argument "null" explicite (mais de type nul implicite) sélectionne toujours sans ambiguïté une surcharge spécifique ??
peterk
4

nullest une valeur valide pour l'un des trois types; donc le compilateur ne peut pas décider quelle fonction utiliser. Utilisez quelque chose comme doSomething((Object)null)ou à la doSomething((Integer)null)place.

Lars Noschinski
la source
J'ai supprimé la méthode avec le paramètre Integer, elle appelle la fonction et renvoie la sortie en tant que "Array Called" , alors quel est le contrat entre Array et Object ?
Phani
2
Les tableaux Java sont également des objets.
Zds
2

Chaque classe en Java étend la classe Object, et même la classe Integer étend également Object. Par conséquent, Object et Integer sont tous deux considérés comme une instance Object. Ainsi, lorsque vous passez null comme paramètre, le compilateur se confond avec la méthode objet à appeler, c'est-à-dire avec le paramètre Object ou le paramètre Integer, car ils sont tous les deux des objets et leur référence peut être nulle. Mais les primitives de java n'étendent pas Object.

Ankit
la source
1

J'ai essayé cela et quand il y a exactement une paire de méthodes surchargées et que l'une d'elles a un type de paramètre Object, le compilateur sélectionnera toujours la méthode avec un type plus spécifique. Mais lorsqu'il y a plus d'un type spécifique, le compilateur renvoie une erreur de méthode ambiguë.

Puisqu'il s'agit d'un événement au moment de la compilation, cela ne peut se produire que lorsque l'on passe intentionnellement null à cette méthode. Si cela est fait intentionnellement, il est préférable de surcharger à nouveau cette méthode sans paramètre ou de créer une autre méthode.

Jafar Ali
la source
0

il y a une ambiguïté à cause de doSomething (char [] obj) et doSomething (Integer obj).

char [] et Integer sont tous les deux supérieurs pour null, c'est pourquoi ils sont ambigus.

chitrendra chaudhary
la source
0
class Sample{
  public static void main (String[] args) {
       Sample s = new Sample();
       s.printVal(null);

    } 
    public static void printVal(Object i){
        System.out.println("obj called "+i);
    }

    public static void printVal(Integer i){
        System.out.println("Int called "+i);
    }
}

La sortie est Int appelée null et donc l'ambiguïté est avec char [] et Integer

nagarjuna chimakurthi
la source