Вопрос по java – Использование оператора == в Java для сравнения объектов-оболочек

46

Я читаю SCJP Java 6 от Кэти Сьерра и Берт Бейтс, и эта книга меня очень смущает. На странице 245 они заявляют, что следующий код ниже.

<code>Integer i1 = 1000;
Integer i2 = 1000;
if(i1 != i2)
System.out.println("different objects");

//Prints output
different objects
</code>

Затем на следующей странице у них есть следующий код

<code>Integer i3 = 10;
Integer i4 = 10;
if(i3 == i4)
System.out.println("same objects");

//Prints output
same objects
</code>

Я весьма озадачен! Когда я пытаюсь это сделать самостоятельно, кажется, что вы не можете использовать == для сравнения так же, как и метод equals (). Использование == всегда дает мне «ложь», даже если переменные Integer установлены на одно и то же значение (т.е. 10). Я прав? Использование == для сравнения одного и того же целочисленного объекта (с одинаковыми значениями) всегда приводит к значению fal

Ваш Ответ

8   ответов
58

объект стажировки. Java интернирует небольшие числа (менее 128), поэтому все экземплярыInteger(n) сn в интернированном диапазоне одинаковы. Числа больше или равные 128 не интернированы, следовательноInteger(1000) объекты не равны друг другу.

Вау! Я тоже это видел. Зачем?? Это так запутанно. В чем причина этого? dido
Кажется, я помню, что это относится и к маленьким строкам, но я не уверен, правда ли это, и если да, то, что считается маленькой строкой. Вы знаете что-нибудь об этом? G. Bach
@ G.Bach Нет, это не имеет ничего общего с размером. Строковые константы интернированы, и вы можете позвонитьintern на строковые переменные для того же эффекта, вот и все. И почему все просто: нам нужно где-то хранить строковые константы, а для маленьких целых чисел это просто оптимизация производительности / памяти Voo
обратите внимание, что только объект, полученный из литералов, автобокс иInteger.valueOf() являются интернированными объектами, в то время как те, которые построены сnew Integer всегда разные объекты ratchet freak
@ dido Одной из причин интернирования целых чисел является попытка сэкономить память и в определенной степени - также сэкономить время. КогдаInteger объекты используются как ключи в хэш-картах или как объекты в хэш-наборах, процент маленьких целых чисел непропорционально велик. Интернируя их, вы можете пропустить перераспределение памяти для хранения идентичных копий неизменных объектов, которые равны друг другу, и позволить равенству сравнения заканчиваться быстрее, проверяя сначала равенство ссылок. Лучше всего то, что это вряд ли стоит вам что-либо с точки зрения циклов процессора, так что это было простое решение. dasblinkenlight
0

кроме примитивных типов, он проверяет равенство ссылок; это применимо даже тогда, когда сравниваемые вещи являются обернутыми примитивами. Далее,valueOfетод @ и сгенерированный компилятором оператор автобокса, как правило, могут произвольно возвращать новый объект, который не будет равняться ссылке на любую другую ранее существующую ссылку, или возвращать ссылку на существующий объект (который, конечно, будет ссылкой - эквивалентно любой ранее существующей ссылке, идентифицирующей тот же объект). Реализации должны поддерживать "пул"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, фактически не заметив, что он не совпадает, следует считать нарушенным.

0

т логические результаты не так, как мы ожидаем. Поэтому будьте осторожны и убедитесь, что возможные неизвестные результаты не влияют на производительность, надежность и точность вашего программного обеспечения.

2
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 при запуске программы (по умолчанию это значение от -127 до 128).

17

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 выполняет пул (такой как стажер String). В случае Integer, это сам класс, который делает пул. Там нет магии JVM.

На самом деле, кешированиеInteger объекты дляint значения в диапазоне [-128, 127] указаны в Документы API, так что эта часть диапазона, на самом деле, гарантирована. Ted Hopp
7

чтобы рассмотреть, хотя, если вы делаете:

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. он загружает его из кэша.

0

"==" всегда сравнивают места в памяти или ссылки на объекты значений.. Но метод equals также косвенно использует оператор "==" для сравнения значений. Integer использует кэш 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

Ссылка на ссылку для дополнительной информации

0

Согласно с 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() {}
}
Ссылк JLS-5.1.7 Код класса IntegerInteger Java Doc

Похожие вопросы