Сравнение примитива с объектом-оболочкой с необработанным поведением
У меня есть фрагмент кода, который мне нужно понять:
public static void main(String[] args) {
Character c = new Character('a');
Character cy = new Character('a');
char cx = 'a';
System.out.println(c == cx);
System.out.println(cx == cy);
System.out.println(c == cy);
}
Вывод:
true
true
false
Я не могу понять, почему только третий оператор терпит неудачу.
EDIT: этот вопрос отличается от вопроса .equals
vs ==
как это о сравнении примитивов и объектов.
Ответы
Ответ 1
c
и cy
относятся к разным экземплярам класса Character
(каждый раз, когда вы вызываете конструктор, вы создаете новый экземпляр), поэтому сравнение этих ссылок возвращает false
.
С другой стороны, когда вы сравниваете любой из них с примитивным cx
, они распаковываются в char
, а сравнение char
возвращает true.
Если бы вы использовали Character.valueOf('a')
вместо new Character('a')
, вы бы получили тот же экземпляр в обоих вызовах, и ссылочное сравнение вернуло бы true
(так как valueOf
возвращает экземпляр кешированного Character
, если аргумент <= 127).
Ответ 2
System.out.println(c == cx);
System.out.println(cx == cy);
Так как один является примитивным, а другой является его классом-оболочкой, unboxing происходит, и выполняется примитивное сравнение (==).
В то время как:
System.out.println(c == cy);
- сравнение объектов. Различные экземпляры сравниваются, поэтому ==
не будет работать в этом случае.
Ответ 3
класс Charcter не является одиночным, поэтому всегда создается новый объект при вызове конструктора, а новые объекты ссылаются на соответствующие ссылки.
(c == cy)
дает вам false
Ответ 4
очевидно, почему последнее сравнение дает false
: оба Character
явно инициализируются с помощью new
, поэтому являются разными объектами
почему первые два сравнения дают true
, однако, только отчасти ясны: значение char
определенно используется для извлечения предварительно сохраненного экземпляра Character
, но я не знаю, определенные объекты Character
сопоставляются с этим предварительно сохраненным экземпляром
Я бы ожидал, однако, он работает как "==" - сравнение для объектов String
: если во время компиляции один из сравниваемых экземпляров является предварительно сохраненным Character
, тогда компилятор вставляет вызов equals()
заменяя "==" - сравнение