Использование оператора == в Java для сравнения объектов-оболочек
Я читаю SCJP Java 6 Кэти Сиерры и Берта Бейтса, и эта книга меня очень смущает. На странице 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', даже если целочисленные переменные имеют одинаковое значение (например, 10). Я правильно? Использование == для сравнения одного и того же целого объекта (с одинаковыми значениями) всегда приводит к 'false'
8 ответов:
Ключ к ответу называетсяинтернирование объекта . Java интернирует небольшие числа (меньше 128), поэтому все экземпляры
Integer(n)сnв интернированном диапазоне одинаковы. Числа, большие или равные 128, не интернируются, следовательно, объектыInteger(1000)не равны друг другу.
Если вы посмотрите на исходный код для
Integer,вы увидите, чтоInteger.valueOf(int)пулы все значения от -128 до 127. Причина в том, что небольшие целочисленные значения используются часто и поэтому заслуживают объединения в пул/кэш.Взято прямо из
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 выполняет объединение (например, стажер строки). В случае Integer это сам класс, который делает объединение. Здесь нет никакой магии СПМ.
Приведенный выше ответ об интернировании верен. Что-то, чтобы рассмотреть, хотя, если вы делаете:
Integer i3 = new Integer(10); Integer i4 = new Integer(10);У вас не будет новых объектов, так как вы создали новые объекты явно. Если вы напишете код следующим образом, он будет интернирован:
Теперь они снова будут одним и тем же объектом. Если вы посмотрите на метод valueOf внутри целого числа.класс java в src.zip-файл вы можете увидеть, где он проверяет, находится ли значение int за пределами от -128 до 127 он вызывает новый целочисленный класс иначе он загружает его из кэша.Integer i3 = Integer.valueOf(10); Integer i4 = Integer.valueOf(10);
Integer i1 = 1000; Integer i2 = 1000;Компилятор "упаковывает" int 1000 как целочисленный объект. Для этого он преобразует источник в следующий:
Integer i1 = Integer.valueOf(1000); Integer i2 = Integer.valueOf(1000);Теперь
valueOfможет быть простым вызовомnew Integer(1000), однако создание нового целочисленного объекта каждый раз, когдаintпомещается в коробку, будет стоить как времени, так и пространства. Чтобы избежать этого, класс 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).
Когда оператор 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, не наблюдая на самом деле, что она не соответствует, должен считаться сломанным.
Сравнение строк и целых чисел с помощью = = и != дает булевы результаты не так, как мы expect.So будьте осторожны и убедитесь , что возможные неизвестные результаты не препятствуют производительности, надежности и точности вашего программного обеспечения.
"== " Всегда сравнивайте расположение в памяти или ссылки на объекты значений. метод equals всегда сравнивает значения.но equals также косвенно использует оператор "= = " для сравнения значений. Integer использует целочисленный кэш для хранения значений от -128 до +127.Если оператор == используется для проверки любых значений от -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Обратитесь по ссылке для получения дополнительной информации
Согласно jls-5.1.7
If the value p being boxed is true, false, a byte, or a char in the range \u0000 to \u007f, or an int or short number between -128 and 127 (inclusive), then let r1 and r2 be the results of any two boxing conversions of p. It is always the case that r1 == r2.Итак, любое число между -128 и еще 127 кэшируется классом Interger.
Код кэширования записывается в классе
Помните, что при сравнении двух объектов всегда используйте методequals.IntegerCache, который является членом классаInteger.Вот фрагмент кода:
/** * Cache to support the object identity semantics of autoboxing for values between * -128 and 127 (inclusive) as required by JLS. * * The cache is initialized on first usage. The size of the cache * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option. * During VM initialization, java.lang.Integer.IntegerCache.high property * may be set and saved in the private system properties in the * sun.misc.VM class. */ private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } private IntegerCache() {} }Ссылки
Comments