public class Test {
public static void main(String[] args) {
String s = null;
String s1 = null;
Integer i = null;
Integer i1 = null;
System.out.println(s+i);
System.out.println(i+s);
System.out.println(s+s1);
try {
System.out.println(i+i1);
} catch (NullPointerException np) {
System.out.print("NullPointerException");
}
}
}
La question est simple: pourquoi reçois-je une NullPointerException
uniquement à la dernière ligne?
Votre code utilise deux opérateurs différents - additifs . Les trois premières lignes utilisent chaîne de concaténation , tandis que la dernière utilise addition numérique .
La concaténation de chaînes est bien définie pour transformer null
en "null"
:
- Si la référence est
null
, elle est convertie en chaîne"null"
(quatre ASCII caractèresn
,u
,l
,l
).
Il n'y a donc pas de NPE.
Ajouter deux objets Integer
ensemble nécessite qu'ils soient unboxed . Cela entraîne le déréférencement de la référence null
, ce qui conduit au NPE:
- Si
r
est null, la conversion unboxing génère uneNullPointerException
Notez que les trois premières utilisations de l'opérateur +
impliquent une concaténation de chaînes. Seul le dernier correspond au nombre réel somme . Lorsque la concaténation de chaînes est impliquée (où la variable s
est impliquée), le compilateur Java utilise une astuce intelligente pour améliorer les performances. Il remplace l'opérateur +
par StringBuilder
. Par exemple, votre première ligne est traduite en:
StringBuilder tmp = new StringBuilder();
tmp.append(s);
tmp.append(i);
System.out.println(tmp);
StringBuilder
est null
- friendly donc, peu importe ce que vous transmettez comme argument, il le remplace joliment par "null"
chaîne.
La situation est différente à la dernière ligne. Là, vous faites référence à deux objets Integer
. La seule chose que la JVM puisse faire ici est de les déballer (i.intValue()
) et d’effectuer le calcul proprement dit. Unboxing de null
cause NullPointerException
.
La concaténation (opérateur +
) de tout ce qui a un String
aboutit à un String
name__. Chaque opérande est d'abord converti en chaîne (à l'aide de toString()
ou de la valeur "null"
), puis concaténé.
Mais la dernière opération implique uniquement Integer
name__s, de sorte que les règles précédentes ne s'appliquent pas. Au lieu d'une concaténation, il s'agit d'une addition. Mais pour ajouter deux Integer
name__s, il convertit les objets (Integer
name__s) en valeurs primitives (int), ce qui n'est pas possible si Integer
est null. C'est pourquoi vous obtenez un NullPointerException
name__.
Semble être un cas d'auto-déballage. Si vous avez deux Integer
s first
et second
, le résultat de leur addition sera first.intValue() + second.intValue()
. Étant donné que les deux sont nuls, il en résulte un NPE.
Il convient de noter que la réponse à cette question aurait dû être évidente:
C:\Temp>Java Test
nullnull
nullnull
nullnull
NullPointerException
Jetez un coup d'œil au bytecode pour votre programme. Vous remarquerez que votre objet null est transmis en tant que paramètre à la méthode PrintStream.print (). Le code source de la méthode print () utilise String.valueOf () comme indiqué ci-dessous:
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}