Использование оператора == в Java для сравнения объектов-оболочек
Я читаю SCJP Java 6 от Kathy Sierra и Bert Bates, и эта книга меня так запутывает. На стр. 245 указано, что следующий код ниже.
Integer i1 = 1000;
Integer i2 = 1000;
if(i1 != i2)
System.out.println("different objects");
//Prints output
different objects
Затем на самой следующей странице есть следующий код
Integer i3 = 10;
Integer i4 = 10;
if(i3 == i4)
System.out.println("same objects");
//Prints output
same objects
Я так смущен! Когда я пытаюсь это сделать самостоятельно, кажется, что вы не можете использовать == для сравнения так же, как вы бы использовали метод equals(). Использование == всегда дает мне "false", даже если переменные Integer установлены на одно значение (т.е. 10). Я прав? Использование == для сравнения одного и того же объекта Integer (с одинаковыми значениями) всегда приведет к "false"
Ответы
Ответ 1
Ключ к ответу называется интернированием объектов. Java ставит небольшие числа (менее 128), поэтому все экземпляры Integer(n)
с n
в интернированном диапазоне одинаковы. Числа, которые больше или равны 128, не интернированы, поэтому объекты Integer(1000)
не равны друг другу.
Ответ 2
Если вы посмотрите на исходный код для Integer
, вы увидите, что Integer.valueOf(int)
пулы все значения от -128 до 127. Причина в том, что небольшие значения Integer используются часто и, таким образом, достойный объединения/кэширования.
Взято прямо из Integer.java
:
public static Integer valueOf(int i) {
if(i >= -128 && i <= IntegerCache.high)
return IntegerCache.cache[i + 128];
else
return new Integer(i);
}
Обратите внимание, что этот пул является специфичным для реализации и нет гарантии объединенных диапазонов.
Ответы о интернинге верны в концепции, но неверны с терминологией. Интернатура в Java обычно подразумевает, что среда выполнения Java выполняет объединение (например, String intern). В случае Integer это сам класс, который выполняет объединение. Там не задействована магия JVM.
Ответ 3
Вышеприведенный ответ о Interning справедлив. Что-то нужно учитывать, если вы это сделаете:
Integer i3 = new Integer(10);
Integer i4 = new Integer(10);
У вас не будет новых объектов, так как вы создали новые объекты. Если вы напишете код следующим образом, он будет интернирован:
Integer i3 = Integer.valueOf(10);
Integer i4 = Integer.valueOf(10);
Теперь они снова будут тем же самым объектом. Если вы посмотрите на метод valueOf внутри класса Integer.java в файле src.zip, вы увидите, где он проверяет, не превышает ли значение int значение от -128 до 127, он вызывает новый класс Integer иначе он загружает его из кеша.
Ответ 4
Integer i1 = 1000;
Integer i2 = 1000;
Компилятор "блокирует" int 1000 как объект Integer. Для этого он преобразует источник в следующее:
Integer i1 = Integer.valueOf(1000);
Integer i2 = Integer.valueOf(1000);
Теперь valueOf
может быть простым вызовом new Integer(1000)
, но при создании нового объекта Integer каждый раз, когда поле int
вставляется в квадрат, будет стоить как время, так и пробел. Чтобы этого избежать, класс Integer хранит массив объектов Integer для ограниченного диапазона значений int.
if(value> maxRange || value< minRange){
//not in pool return new Integer
return new Integer(value);
}else{
//return pooled Integer object
//for the value, pool contains all Integer
//values from minRange to maxRange
return integerPool[value-minRange];
}
Скорость, полученная против потерянной памяти, может быть отрегулирована путем установки диапазона с помощью аргумента jvm при запуске программы (по умолчанию afaik -127 - 128).
Ответ 5
Когда оператор Java == используется для сравнения чего-либо, кроме примитивных типов, он проверяет ссылочное равенство; это применимо даже тогда, когда сравниваемые вещи являются обернутыми примитивами. Кроме того, метод valueOf
и сгенерированный компилятором оператор autoboxing, как правило, могут произвольно возвращать новый объект, который не будет равным ссылке на любую другую ранее существующую ссылку или возвращать ссылку на существующий объект (который, конечно, быть ссылочным равным любой ранее существующей ссылке, идентифицирующей тот же объект). Реализации необходимы для поддержки "пула" экземпляров Integer
для значений от -128 до 127, так что все вызовы Integer.valueOf
на любом конкретном номере в этом диапазоне будут возвращать ссылки на один и тот же объект, но кроме этого реализация было бы свободно делать что-то вроде
static Integer [] intPool = new Integer[256];
public Integer valueOf(int n)
{
int hash = (n*0x18675309) >>> 24;
Integer instance = intPool[n];
if (instance == null && instance.value != n)
{
instance = new Integer(n);
intPool[hash] = instance ;
}
return instance;
}
Я особо не ожидаю, что реализации Java будут делать что-то подобное, поскольку во многих случаях отношение "кэш-атака" может быть около 0%, а дополнительное время, затрачиваемое на поиск экземпляров в кеше, будет потрачено впустую. Тем не менее, никогда не было никакой гарантии, что ссылка, возвращаемая instanceOf
, не будет соответствовать некоторой предыдущей ссылке, возвращенной этим методом (даже если она не соответствует последней ссылке, возвращаемой этим методом, некоторые алгоритмы кэширования могут привести к ее возвращает более раннюю ссылку, особенно если пул разделяется несколькими потоками без блокировки. Отсутствие блокировки никогда не приведет к тому, что код вернет что-либо, кроме ссылки на целое число с правильным значением, но может вызвать непредсказуемые изменения, в которых возвращаемые ссылки сравните равные). Только ссылки на объекты Integer
, созданные напрямую с использованием конструктора new Integer(n)
, гарантируют уникальность; код, который ожидает, что какая-либо ссылка, возвращаемая valueOf
, не соответствует какой-либо ссылке, возвращаемой valueOf
, не заметив, что она не соответствует, должна считаться нарушенной.
Ответ 6
Сравнение строк и целочисленное сравнение с использованием == и!= дает булевы результаты не так, как мы ожидаем. Будьте осторожны и убедитесь, что возможные неизвестные результаты не мешают производительности, надежности и точности вашего программного обеспечения.
Ответ 7
"==" всегда сравнивать расположение памяти или ссылки на объекты значений.
equals всегда сравнивает значения. но равно также косвенно использует оператор "==" для сравнения значений. Integer использует Integer cache для хранения значений от -128 до +127.If == оператор используется для проверки любых значений от -128 до 127, тогда он возвращает true. если какое-либо значение между -128 и 127 как
Integer i1 = -128;
Integer i2 = -128;
System.out.println(i1 == i2); // returns true
кроме указанного выше диапазона, он возвращает false
Integer i1 = 1000;
Integer i2 = 1000;
System.out.println(i1 == i2); // returns false
Обратитесь к ссылке за дополнительной информацией