Сравнение Java-оболочки - PullRequest
0 голосов
/ 08 мая 2018
public static void main(String[] args) {    
    System.out.println((Integer.valueOf("5000") <= Integer.valueOf("5000")));
    System.out.println((Integer.valueOf("5000") == Integer.valueOf("5000")));       
}

Приведенный выше код печатает true и false соответственно. Это понятно, но почему печатается false, когда мы используем ==.

Но когда используется <= (меньше или равно), почему ответ true?

Ответы [ 4 ]

0 голосов
/ 08 мая 2018

На этот вопрос легко ответить, если вы проверите документацию Java для Integer.valueOf(String s):

public static Integer valueOf (String s) выдает NumberFormatException

Возвращает Целочисленный объект , содержащий значение указанной строки. Аргумент интерпретируется как представление десятичного целого числа со знаком, точно так же, как если бы аргумент был передан методу parseInt (java.lang.String). Результатом является объект Integer, представляющий целочисленное значение, указанное в строке. Другими словами, этот метод возвращает целочисленный объект , равный значению:

   new Integer(Integer.parseInt(s))

Поскольку Integer.valueOf("5000") возвращает объект Integer вместо примитива int, и, тем не менее, вы сравниваете объекты, используя ==, вы получите false, если оба объекта Integer не указывают на одну и ту же ссылку.

  • == проверяет равенство путем сравнения идентичности объектов.

  • .equals() проверяет равенство путем сравнения содержимого объектов.

Когда вы сравниваете объекты с <, >, <= или >=, это даст вам неточные результаты, потому что вы этого не делали и не можете выполнять перегрузку операторов в Java (то есть определяете пользовательские поведения для ваши операторы и подскажите им как сравнивать объект).

Если вы хотите сравнить объект, реализуйте Comparable в классе. Если вы хотите сравнить объект Integer, получите примитивное значение int, прежде чем сравнивать их, используя >, <, >= или <=:

Integer.valueOf("5000").intValue() <= Integer.valueOf("5000").intValue();  //true
0 голосов
/ 08 мая 2018

При сравнении классов-оболочек с использованием <=, >= Java выполняет распаковку и сравнивает фактические значения типа int (или double, long и т. Д.) Между собой. Так что Integer.valueOf("5000") <= Integer.valueOf("5000") будет работать так Integer.valueOf("5000").intValue() <= Integer.valueOf("5000").intValue(), что эквивалентно 5000 <= 5000.

0 голосов
/ 08 мая 2018

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

Я декомпилировал ваш код до уровня байт-кода.

Для 1-й строки:

System.out.println((Integer.valueOf("5000") <= Integer.valueOf("5000")));

Байт-код (бесполезная информация удалена):

LDC "5000"
INVOKESTATIC java/lang/Integer.valueOf (Ljava/lang/String;)Ljava/lang/Integer;  
INVOKEVIRTUAL java/lang/Integer.intValue ()I
LDC "5000"
INVOKESTATIC java/lang/Integer.valueOf (Ljava/lang/String;)Ljava/lang/Integer;
INVOKEVIRTUAL java/lang/Integer.intValue ()I
IF_ICMPGT L1

Вы можете увидеть для левой части из <=, JVM использует функцию Integer.valueOf для преобразования строки в объект типа Integer. Затем используйте функцию Integer.intValue, чтобы извлечь внутреннее значение этого объекта (также , называемое автоматическим распаковыванием ). Итак, для левой части мы получаем значение int.

Правая часть <= такая же, как левая часть.

Последняя строка IF_ICMPGT, для сравнения этих двух значений int. Итак, вывод таков: если вы используете <=, компилятор Java сделает для вас автоматическую распаковку и сравнит внутренние значения int.

Для 2-й строки:

System.out.println((Integer.valueOf("5000") == Integer.valueOf("5000")));

Байт-код (бесполезная информация удаляется):

LDC "5000"
INVOKESTATIC java/lang/Integer.valueOf (Ljava/lang/String;)Ljava/lang/Integer;
LDC "5000"
INVOKESTATIC java/lang/Integer.valueOf (Ljava/lang/String;)Ljava/lang/Integer;
IF_ACMPNE L4

Вы видите, что байт-код отличается от 1-й строки. Он просто конвертирует строки в целочисленные объекты, но НЕ автоматически распаковывает их. А поскольку они представляют собой два отдельных объекта, они должны иметь разные адреса (в памяти).

Последняя строка IF_ACMPNE будет сравнивать адреса этих двух целочисленных объектов. Итак, вывод таков: если вы используете ==, компилятор Java не сделает автоматическую распаковку для вас и сравнит адреса объектов.

Что еще

Класс Integer кэширует Целочисленные объекты для диапазона -128 ~ 127. Это означает, что если вы передадите строку с этим диапазоном, вы получите точно такой же объект Integer. Ниже код напечатает true:

System.out.println((Integer.valueOf("127") == Integer.valueOf("127"))); // true
0 голосов

Оператор равенства == между двумя объектами означает ссылочное равенство ; они должны ссылаться на один и тот же объект, поскольку их адреса памяти одинаковы. Это относится и ко всем упаковщикам.

Два объекта могут быть «равными» по значению, например, если все его поля равны, но занимают разные адреса памяти. Integer - это объект-оболочка для примитива int.

Поскольку Integer (и все объекты Wrapper) являются объектами, a == b, где a, b - целые числа (не целые), вернет true, если a, b ссылается на тот же объект Integer.

Во втором System.out.println вы создали два новых целочисленных объекта, (Integer.valueOf("5000"), (Integer.valueOf("5000"), где они оба содержат одинаковые упакованные значения типа int. Но эти целые числа занимают два разных адреса памяти , поэтому эти два не могут быть равными ссылочным. Поэтому, поскольку они не равны эталонному значению, == оценивается как False.

С другой стороны, оператор "меньше или равно" <= вообще не определен в объектах. Строка Integer.valueOf("5000") <= Integer.valueOf("5000"), включает в себя "распаковку" целых чисел, а затем сравнение значения его int value и возвращает true, если значение первого поля Integer (типа int) равно значению второго поля Integer. Java выполняет распаковку класса Integer при сравнении неравенства.

...