Метод equals() в Java неожиданно работает на длинном типе данных
Сначала рассмотрим следующие выражения в Java.
Integer temp = new Integer(1);
System.out.println(temp.equals(1));
if(temp.equals(1))
{
System.out.println("The if block executed.");
}
Все эти утверждения работают нормально. В этом нет никаких сомнений. Выражение temp.equals(1)
оценивается как true
, как ожидалось, и поэтому выполняется только оператор внутри блока if
.
Теперь, когда я изменяю тип данных от Integer
до Long
, оператор temp1.equals(1)
неожиданно оценивается как false
следующим образом.
Long temp1 = new Long(1);
System.out.println(temp1.equals(1));
if(temp1.equals(1))
{
System.out.println("The if block executed.");
}
Это эквивалентные утверждения, упомянутые в предыдущем фрагменте, только тип данных был изменен, и они ведут себя совершенно противоположно.
Выражение temp1.equals(1)
оценивается как false
, и, следовательно, единственный оператор в блоке if
не выполняется, чем обратное предыдущим операторам. Как?
Ответы
Ответ 1
Вы сравниваете Long
с int
. В javadoc для java.lang.Long#equals
говорится, что метод equals
Сравнивает этот объект с указанным объектом. Результат является истинным тогда и только тогда, когда аргумент не является нулевым и является объектом Long, который содержит такое же длинное значение, что и этот объект.
Вместо этого попробуйте System.out.println(new Long(1).equals(1L));
Теперь, когда вы сравниваете Long
с Long
вместо Long
с Integer
, он печатает true
.
Ответ 2
Литеральное значение 1
не является long
, это a int
. Вместо этого попробуйте использовать приведенный выше код:
System.out.println(temp1.equals(1L));
и
if (temp1.equals(1L))
Как вы можете видеть, добавление L
после литерального значения 1
означает, что это a long
, а затем сравнения работают как ожидалось.
Ответ 3
Причина, по которой вы можете сделать это сравнение, связана с автобоксированием в Java.
Фактический метод, который вы вызываете, таков:
http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Long.html#equals(java.lang.Object)
который сравнивает ваш объект Long с каким-либо другим объектом, а не с фактическим примитивным int.
Что происходит при вызове метода, так это то, что ваш примитив integer(1)
автобоксирован в Object(Integer)
, после чего вы фактически вызываете:
new Long(1).equals(new Integer(1));
поэтому он терпит неудачу.
Вот почему, если вы вызываете
new Long(1).equals(1L)
это сработало бы, потому что Java будет автобокс 1L
(примитивный long
, not int
) в объект long
, а не объект Integer
.
Ответ 4
Согласно странице Javadoc на Long
, .equals
метод оценивается true
только в том случае, если
- Аргумент - это объект
Long
- Если (1) истинно, то объекты
Long
должны иметь равные значения
В вашем сценарии 1
есть объект int
, а не Long
, поэтому он терпит неудачу (1) и, следовательно, оценивает значение false. Если вам нужно проверить значение Long
, используйте 1L
.
Ответ 5
Java ленив.
Когда вы выполните следующее сравнение, java автоматически перенесет int в long (поскольку long может содержать любое значение, которое может содержать int). И сравнение между двумя длинными, а не двумя ints.
int i = 1;
long l = 1L;
boolean b = i == l;
Java может это сделать, потому что информация о типе о i
и l
известна во время компиляции и при выполнении сравнения. Однако, когда вы используете коробчатую версию, тип может быть известен во время компиляции, но не при выполнении сравнения. Это связано с тем, что сравнение должно выполняться в методе equals, а поскольку equals принимает Object как параметр, информация о типе теряется. Таким образом, Java ленив и проверяет только, равны ли два бокс-номера, если они оба являются экземплярами одного класса Number (например, Integer или Long, или Double, и т.д.).
Вызывает единственный полностью надежный способ сравнения двух чисел неизвестного типа во время выполнения - это преобразовать оба значения в строки и оба в BigDecimal, а затем использовать метод compareTo (и не). Хотя, если вы знаете, что вы когда-либо будете получать долги и ints, тогда жизнь проще, поскольку вы можете просто сделать следующее.
Number n0 = new Long(1L);
Number n1 = new Integer(1);
boolean equal = n0.longValue() == n1.longValue();
Ответ 6
Это поведение согласуется с autoboxing, преобразующим 1
в Integer
, который затем сравнивается с другим Integer(1)
. Сравнение a Long
с a Integer
дает false
.
Если вы использовали бы 1L
для сравнения с Long
, он дал бы true
.
Ответ 7
Длинные temp1 = новые Длинные (1); System.out.println(temp1.equals(1));
if (temp1.equals(1)) { System.out.println( "Выполняется блок if" ); }
в этом коде temp1.equals(1)
сравнивается объект Long
с объектом Integer
, который дает результат false, мы можем исправить его, используя 1L
вместо 1
,, eg temp1.equals(1L)
, мы сравниваем объект Long
с Long
и получаем результат TRUE
Ответ 8
Реализация equals()
метод класса Long иллюстрирует, почему:
public boolean equals(Object obj) {
if (obj instanceof Long) {
return value == ((Long)obj).longValue();
}
return false;
}
Ответ 9
Метод equals в Java.lang.Long сначала начинается с проверки экземпляра SingleOff только после этого, когда сравнивается значение.
public boolean equals(Object obj) {
if (obj instanceof Long) {
return value == ((Long)obj).longValue();
}
return false;
}
Итак, если вы собираетесь использовать, а Integer Value - в месте длинного значения, тогда первая проверка завершится неудачно и, следовательно, вы получите false в качестве результата.
Ответ 10
Вы можете сравнивать значения Long/integer без ut equals(). Это необходимо, только когда вы сравниваете строки, насколько мне известно.