Нулевые значения строк и целых чисел в Java
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");
}
}
}
Вопрос прост: почему я получаю NullPointerException
только в последней строке?
Ответы
Ответ 1
В вашем коде используются два разных аддитивных оператора. В первых трех строках используется конкатенация строк, в то время как последняя использует числовое добавление.
Конкатенация строк четко определена, чтобы превратить null
в "null"
:
- Если ссылка
null
, она преобразуется в строку "null"
(четыре символа ASCII n
, u
, l
, l
).
Следовательно, нет NPE.
Добавление двух объектов Integer
вместе требует, чтобы они были unboxed. Это приводит к разрыву ссылки null
, которая приводит к NPE:
- Если
r
имеет значение null, то при распаковке преобразование выбрано NullPointerException
Ответ 2
Обратите внимание, что первые три оператора оператора +
связаны с конкатенацией строк. Только последняя является фактической числовой суммой. Когда задействована конкатенация строк (где задействуется переменная s
), компилятор Java использует некоторые умные трюки для повышения производительности. Он заменяет оператор +
на StringBuilder
. Например, ваша первая строка переведена на:
StringBuilder tmp = new StringBuilder();
tmp.append(s);
tmp.append(i);
System.out.println(tmp);
StringBuilder
null
- дружелюбно, поэтому независимо от того, что вы передаете в качестве аргумента, он красиво заменяет его строкой "null"
.
В последней строке ситуация различна. Там вы ссылаетесь на два объекта Integer
. Единственное, что JVM может сделать здесь, это распаковать их (i.intValue()
) и выполнить фактическое вычисление. Unboxing null
вызывает NullPointerException
.
Ответ 3
Конкатенация (оператор +
) всего с String
приводит к a String
. Каждый операнд сначала преобразуется в String (либо используя toString()
, либо используя значение "null"
), затем конкатенируется.
Но последняя операция включает только Integer
, поэтому предыдущие правила не применяются. Вместо конкатенации он делает дополнение. Но чтобы добавить два Integer
s, он преобразует объекты (Integer
s) в примитивные значения (int), что невозможно, если Integer
равно null. Вот почему вы получаете NullPointerException
.
Ответ 4
Кажется, это случай автоматической распаковки. Если у вас есть два Integer
first
и second
, то результатом их добавления будет first.intValue() + second.intValue()
. Поскольку оба они ноль, что приводит к NPE.
Ответ 5
Посмотрите на байт-код для вашей программы. Вы заметите, что ваш нулевой объект передается как параметр метода PrintStream.print(). Исходный код для метода print() использует String.valueOf(), как показано ниже:
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
Ответ 6
Следует отметить, что ответ на этот вопрос должен был быть очевиден на выходе:
C:\Temp>java Test
nullnull
nullnull
nullnull
NullPointerException