Работает ли == на самом деле одинаково или по-разному при сравнении двух примитивов с двумя объектами в Java? - программирование
Подтвердить что ты не робот

Работает ли == на самом деле одинаково или по-разному при сравнении двух примитивов с двумя объектами в Java?

При поиске объяснений того, как логическое равенство == работает в Java, ответы всегда будут выглядеть примерно так:

  • Для примитивов возвращается, имеют ли примитивы одинаковое значение (это включает сравнение примитива с его WrapperObject, когда WrapperObject автоматически распаковывается в примитив).
  • Для объектов возвращается, представляют ли они один и тот же объект в куче.

Но все эти объяснения, кажется, подразумевают, что это две разные вещи, что == ведет себя по-разному в зависимости от того, сравниваете ли вы Objects с примитивами. Мне кажется, что на самом деле это должно быть одно и то же: взять две переменные из стека и сравнить их значения.

Меняется не поведение ==, а то, что представляют собой сравниваемые значения. Если вещи, которые вы сравниваете, являются примитивами, то значение в стеке - это значение самого примитива. Если вы сравниваете объекты, то значение в стеке является значением ссылки (и, следовательно, адресом объекта в куче).

Я что-то неправильно понял, или же == ведет себя одинаково во всех ситуациях? Бонусные баллы, если вы можете указать мне документацию о том, как это действительно работает под прикрытием.

4b9b3361

Ответ 1

Как говорят другие ответы/комментарии, на уровне языка Java семантика оператора == определяется (в JLS 15.21) независимым от реализации способом. Строго говоря, вы не можете вывести детали реализации "изнутри" из текста JLS. Все, что вы можете сказать, это то, что любая совместимая реализация == должна вести себя определенным образом.

I will assume that we are talking about conventional JVMs where the actual machine representation of a reference is a machine address. It is possible to implement references in other ways; e.g using some kind of indirect addressing mechanism such as a PIDLAM.

На уровне байт-кода существует ряд различных инструкций байт-кода, которые реализуют логику == в зависимости от типа (int, long или ссылки). Однако семантика сравнений схожа. Как только байт-коды проверены как безопасные по типу, целые числа и адреса могут обрабатываться одинаково для целей сравнения == на аппаратном уровне.

На аппаратном уровне (машинная инструкция) == работает одинаково для примитивных целочисленных типов и не примитивных значений. В обоих случаях это будет выполнение машинной инструкции, которая сравнивает два "слова", взятые из регистра или из памяти (куча или стек).


Указанная в JLS семантика == для float и double немного отличается, потому что специальные значения (значения бесконечности и не числа) требуют специальной обработки. Например: NaN == NaN - это false. См. также стандарт IEEE 754 с плавающей запятой.

Для этого существуют разные байт-коды, и на аппаратном уровне используемые инструкции отличаются от тех, которые используются в целочисленных и ссылочных случаях. (Обработка специальных значений обычно обрабатывается в плавающем оборудовании.)


Указанная в JLS семантика == для boolean, byte, short и char предназначена для преобразования значений в другой тип (int, long, float или double) до сравнивая их. Повышение также происходит в других случаях, если операнды имеют разные (неупакованные) типы.

Кроме того, распаковка происходит, если один (но не оба!) Из операндов упакован. Если оба операнда упакованы, тогда == является сравнительным сравнением.


Резюмируя вышесказанное...

Я что-то неправильно понял или == на самом деле ведет себя одинаково во всех ситуациях?

Нет, если вы включаете типы с плавающей запятой и соображения по расширению и распаковке примитивов.

Бонусные баллы, если вы можете указать мне документацию о том, как это действительно работает под прикрытием.

Для этого нет официальной (Oracle) публичной документации. Спецификации JLS и JVM не предписывают стратегии реализации.

Ответ 2

Я понимаю ваше объяснение, и это правильно, учитывая определенные определения терминов. Но это не соответствует тому, как Java говорит об объектах и примитивах.

Идея "ссылки" на объект в Java серьезно преуменьшается; Я думаю, что возможно быть "программистом Java" и не очень понимать, что такое ссылка. Вы можете запомнить правила, где это имеет значение - оператор '==', передача параметров в методы - и не понять, как это реализовано или может быть реализовано.

Поэтому я думаю, что для многих людей, которые программируют на Java, было бы странно сказать, что == "ведет себя одинаково во всех ситуациях", потому что это требует слишком много знаний "под прикрытием". Java не поощряет вас (или требует от вас) смотреть "под прикрытием" в такой степени.