Pergunta sobre java, integer, operator-keyword, equals, wrapper – Usando o operador == em Java para comparar objetos wrapper

46

Eu estou lendo SCJP Java 6 por Kathy Sierra e Bert Bates e este livro está me confundindo muito. Na página 245 eles afirmam que o seguinte código abaixo.

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

//Prints output
different objects
</code>

Então na próxima página eles têm o seguinte código

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

//Prints output
same objects
</code>

Estou tão confuso! Quando eu tento isso por conta própria, parece que você não pode usar o == para comparar da mesma maneira que você usaria o método equals (). Usar o == sempre me dá 'false' mesmo se as variáveis ​​Integer forem definidas com o mesmo valor (ou seja, 10). Estou correcto? Usar o == para comparar o mesmo objeto Integer (com os mesmos valores) sempre resultará em 'false'

Sua resposta

8   a resposta
7

no entanto, se você fizer:

<code>Integer i3 = new Integer(10);
Integer i4 = new Integer(10);
</code>

Você não terá os novos objetos desde que criou novos objetos explicitamente. Se você escrever o código da seguinte maneira, ele será internado:

<code>Integer i3 = Integer.valueOf(10);
Integer i4 = Integer.valueOf(10);
</code>

Eles serão agora o mesmo objeto novamente. Se você der uma olhada no método valueOf dentro da classe Integer.java no arquivo src.zip você pode ver onde ele verifica se o valor do int está fora de -128 a 127 ele chama a nova classe Integer, caso contrário ele o carrega do cache.

0

"==" sempre compare a localização da memória ou referências de objeto dos valores.. Mas igual também indiretamente usa o operador "==" para comparar os valores. Número inteiro usa o cache Integer para armazenar os valores de -128 a + 127.If == o operador é usado para verificar quaisquer valores entre -128 a 127 e, em seguida, retorna true. se algum valor entre -128 a 127 como

<code>Integer i1 = -128; 
Integer i2 = -128; 
System.out.println(i1 == i2); // returns true
</code>

diferente do intervalo acima, então ele retorna falso

<code>Integer i1 = 1000;
Integer i2 = 1000;
System.out.println(i1 == i2); // returns false
</code>

Indique o link para alguma informação adicional

2
<code>Integer i1 = 1000;
Integer i2 = 1000;
</code>

boxes' o int 1000 como objeto Integer. Para fazer isso, ele converte a fonte para o seguinte:

<code>Integer i1 = Integer.valueOf(1000);
Integer i2 = Integer.valueOf(1000);
</code>

AgoravalueOf poderia ser uma simples chamada paranew Integer(1000) no entanto, criar um novo objeto inteiro toda vez que umint é encaixotado custaria tempo e espaço. Para evitar isso, a classe Integer mantém uma matriz de objetos Integer para um intervalo limitado de valores int.

<code>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];
}
</code>

A velocidade ganha vs. a memória perdida para isto pode ser ajustada definindo o range com um argumento jvm no início do programa (o padrão é afay -127 a 128).

58

objeto internando. Java interns números pequenos (menos de 128), então todas as instâncias deInteger(n) comn na faixa de internados são os mesmos. Números maiores ou iguais a 128 não são internados, portantoInteger(1000) objetos não são iguais entre si.

Java não está internando números pequenos.Integer em si está fazendo o pool de objetos. Steve Kuo
@SteveKuo Você está certo - usei o termo vagamente para significar tanto a linguagem quanto suas bibliotecas, especificamente java.lang.Integer. Os dois são mais ou menos inseparáveis ​​(por exemplo, o compilador Java "sabe" como boxearint constantes comoIntegersEntão eu acho que esse uso é justificado. dasblinkenlight
Já vi casos em que esse internamento causou grave degradação de desempenho. Eu estava criando muitos Integers em um loop apertado, e o custo de instanciação não era trivial. James Scriven
@JamesScriven java não intern internamente dinamicamente, os valores inteiros internados são alocados na inicialização. Só faz uma verificação de intervalo (valor <internedValues.length) quando o autoboxing int. josefx
0

te de tipos primitivos, ele verifica a igualdade referencial; isso se aplica mesmo quando as coisas que estão sendo comparadas são primitivas envolvidas. Além disso, ovalueOf método e autoboxing gerado pelo compilador são geralmente livres para arbitrariamente retornar um novo objeto que não será referência igual a qualquer outra referência existente anteriormente, ou para retornar uma referência a um objeto existente (o que seria, obviamente, referência igual a qualquer referência pré-existente identificando o mesmo objeto). Implementações são necessárias para manter um "pool" deInteger instâncias para os valores -128 a 127, de modo que todas as chamadas paraInteger.valueOf em qualquer número particular dentro desse intervalo irá retornar referências para o mesmo objeto, mas diferente do que uma implementação seria livre para fazer algo como

<code>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;
}
</code>

Eu não espero que as implementações de Java façam algo assim, já que em muitos casos a taxa de "cache hit" pode estar próxima de 0% e o tempo extra gasto procurando instâncias no cache seria desperdiçado. No entanto, nunca há qualquer garantia de que uma referência devolvidainstanceOf não corresponde a alguma referência anterior retornada por esse método (mesmo que não correspondaúltimo referência retornada por esse método, alguns algoritmos de cache podem fazer com que ele retorne ummais cedo referência, especialmente se o pool é compartilhado por vários segmentos sem bloqueio. A falta de bloqueio nunca fará com que o código retorne algo que não seja uma referência a um inteiro com o valor correto, mas pode causar variações imprevisíveis nas quais as referências retornadas se comparam iguais). Apenas referência aInteger objetos criados diretamente usando o construtornew Integer(n) são garantidos como únicos; código que espera qualquer referência retornada porvalueOf para não coincidir com qualquer referência retornada porvalueOf, sem ter realmente observado que não corresponde, deve ser considerado quebrado.

17

Integer você vai ver issoInteger.valueOf(int) piscinas todos os valores -128 a 127. A razão é que valores inteiros pequenos são usados ​​com frequência e, portanto, merecem ser agrupados / armazenados em cache.

Tirada diretamente deInteger.java:

<code>public static Integer valueOf(int i) {
    if(i >= -128 && i <= IntegerCache.high)
        return IntegerCache.cache[i + 128];
    else
        return new Integer(i);
}
</code>

Observe que esse pool é específico da implementação e não há garantia do intervalo em pool.

As respostas sobre internação estão corretas no conceito, mas incorretas na terminologia. Internar em Java normalmente implica que o Java Runtime esteja executando o pooling (como o interno do String). No caso de Integer, é a própria classe que está fazendo o pool. Não há magia da JVM envolvida.

Na verdade, o cache deInteger objetos paraint valores no intervalo [-128, 127] são especificados emos documentos da API, de modo que parte do intervalo é, de fato, garantida. Ted Hopp
0

ecem resultados booleanos não como esperamos. Portanto, tenha cuidado e certifique-se de que os possíveis resultados desconhecidos não prejudiquem o desempenho, a confiabilidade e a precisão de seu software.

0

De acordo comjls-5.1.7

<code>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.
</code>

Então, qualquer número entre-128 e127 é armazenado em cache pela classe Interger.
Lembre-se, ao comparar dois objetos, sempre useequals método.

O código de armazenamento em cache está escrito emIntegerCache classe que é membro deInteger classe.

Aqui está o trecho de código:

<code> /**
 * 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() {}
}
</code>
Referênciasjls-5.1.7Código de classe inteiraInteger Java doc

Perguntas relacionadas