Gebruik == operator in Java om wrapper-objecten te vergelijken

Ik ben SCJP Java 6 van Kathy Sierra en Bert Bates aan het lezen en dit boek brengt me zo in verwarring. Op pagina 245 staat dat de volgende code hieronder staat.

Integer i1 = 1000;
Integer i2 = 1000;
if(i1 != i2)
System.out.println("different objects");
//Prints output
different objects

Op de volgende pagina hebben ze de volgende code

Integer i3 = 10;
Integer i4 = 10;
if(i3 == i4)
System.out.println("same objects");
//Prints output
same objects

Ik ben zo in de war! Als ik dit zelf uitprobeer, lijkt het erop dat je de == niet kunt gebruiken om op dezelfde manier te vergelijken als de methode equals(). Het gebruik van de == geeft me altijd ‘false’, zelfs als de integer-variabelen op dezelfde waarde zijn ingesteld (d.w.z. 10). Ben ik correct? Het gebruik van de == om hetzelfde Integer-object (met dezelfde waarden) te vergelijken, resulteert altijd in ‘false’


Antwoord 1, autoriteit 100%

De sleutel tot het antwoord heet object internering. Java interneert kleine getallen (minder dan 128), dus alle instanties van Integer(n)met nin het geïnterneerde bereik zijn hetzelfde. Getallen groter dan of gelijk aan 128 zijn niet geïnterneerd, daarom zijn Integer(1000)objecten niet gelijk aan elkaar.


Antwoord 2, autoriteit 28%

Als u naar de broncode voor Integerkijkt, ziet u dat Integer.valueOf(int)poolsalle waarden -128 tot 127. De reden is dat kleine Integer-waarden vaak worden gebruikt en daarom het waard zijn om te worden gepoold/gecached.

Rechtstreeks overgenomen van Integer.java:

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

Houd er rekening mee dat deze pooling implementatiespecifiek is en dat er geen garantie is voor het poolbereik.

De antwoorden over stage zijn correct qua concept, maar onjuist qua terminologie. Internering in Java houdt normaal gesproken in dat de Java-runtime de pooling uitvoert (zoals de stagiair van String). In het geval van Integer is het de klasse zelf die de pooling uitvoert. Er komt geen JVM-magie bij kijken.


Antwoord 3, autoriteit 10%

Het bovenstaande antwoord over Interning klopt. Iets om over na te denken als u dat toch doet:

Integer i3 = new Integer(10);
Integer i4 = new Integer(10);

Je hebt de nieuwe objecten niet omdat je expliciet nieuwe objecten hebt gemaakt. Als u de code als volgt schrijft, wordt deze geïnterneerd:

Integer i3 = Integer.valueOf(10);
Integer i4 = Integer.valueOf(10);

Ze zullen nu weer hetzelfde object zijn. Als je de methode valueOf in de klasse Integer.java in het bestand src.zip bekijkt, kun je zien waar het controleert of de waarde van de int buiten -128 tot 127 ligt, anders wordt de nieuwe klasse Integer aangeroepen het laadt het uit de cache.


Antwoord 4, autoriteit 4%

Integer i1 = 1000;
Integer i2 = 1000;

De compiler ‘box’ de int 1000 als integer object. Om dit te doen converteert het de bron naar het volgende:

Integer i1 = Integer.valueOf(1000);
Integer i2 = Integer.valueOf(1000);

Nu zou valueOfeen eenvoudige aanroep kunnen zijn naar new Integer(1000), maar het creëren van een nieuw Integer-object elke keer dat een intin een kader wordt geplaatst, zou kost zowel tijd als ruimte. Om dit te voorkomen, bewaart de klasse Integer een array van Integer-objecten voor een beperkt bereik van int-waarden.

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

De opgedane snelheid versus het geheugen dat hierdoor verliest, kan worden aangepast door het bereik in te stellen met een JVM-argument bij het start van het programma (AFAIK IT standaard is tot -127 tot 128).


5

Stringvergelijking en integervergelijking met == en! = Geeft Booleaanse resultaten niet zoals we verwachten. Dus wees voorzichtig en zorg ervoor dat de mogelijke onbekende uitkomsten de prestaties, betrouwbaarheid en nauwkeurigheid van uw software niet belemmeren.


6

“==” Vergelijk altijd de geheugenlocatie of objectreferenties van de waarden.
Equits-methode Vergelijk altijd de waarden. MAAR gelijken gebruikt ook indirect de operator “==” om de waarden te vergelijken. Integer maakt gebruik van integer-cache om de waarden van -128 tot + 127.if ==-operator op te slaan, wordt gebruikt om te controleren op eventuele waarden tussen -128 tot 127, dan retourneert het waar. Indien een waarde tussen -128 tot 127 als

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

anders dan het bovenstaande bereik, dan retourneert het false

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

verwijs de link voor wat extra info


7

volgens 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.

Dus elk getal tussen -128en 127wordt in de cache opgeslagen door de Interger-klasse.
Onthoud dat bij het vergelijken van twee objecten altijd de methode equalsmoet worden gebruikt.

De cachecode is geschreven in de klasse IntegerCachedie lid is van de klasse Integer.

Hier is het codefragment:

/**
 * 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() {}
}

Referenties

Other episodes