== Integer.valueOf (String) ile karşılaştırmalar 127 ve 128 için neden farklı sonuçlar veriyor?


182

Neden bu kod satırları farklı değerler döndürmek hakkında hiçbir fikrim yok:

System.out.println(Integer.valueOf("127")==Integer.valueOf("127"));
System.out.println(Integer.valueOf("128")==Integer.valueOf("128"));
System.out.println(Integer.parseInt("128")==Integer.valueOf("128"));

Çıktı:

true
false
true

Birincisi trueve ikincisi neden geri dönüyor false? Ben arasına bilmiyorum orada farklı bir şey mi 127ve 128? (Tabii ki biliyorum 127< 128.)

Ayrıca, üçüncüsü neden geri dönüyor true?

Bu sorunun cevabını okudum , ama yine de nasıl dönebileceğini trueve ikinci satırdaki kodun neden döndüğünü alamadım false.


6
Tamsayı bir nesnedir; Eşitlik için karşılaştırma yapmak istiyorsanız, kullanın .equals(), aksi takdirde tüm bahisler kapalıdır.
Karl Damgaard Asmussen

6
@KarlDamgaardAsmussen Aslında burada gerçekten aynı nesneye referans olup olmadıklarını test etmek istiyorum ve ilk başta neden 127 128'in farklı sonuç döndürdüğünü anlamıyorum.
DnR

@DnR Java standartlaştırılmış bir belirtime sahip bir dil olsaydı, bu tür konuların uygulamaya veya hatta zorunlu tanımlanmamış davranışa kadar izin verdiğini düşünürdüm.
Karl Damgaard Asmussen

1
@jszumski: Bu soruda önbellekleme bölümünden daha fazlası var . Ayrıca, bağlantılı cevap en iyi ihtimalle eksiktir - neyin önbelleğe alındığı ve nedeninin ne olduğunun ayrıntılarına girmez.
Makoto

1
Bu tartışmayı daha fazla takip etmek için lütfen bu meta gönderiye bakın .
Jeroen Vannevel

Yanıtlar:


191

Burada çarpıcı bir fark var.

valueOfIntegerdeğerleri -128 ile 127 arasında önbelleğe alınmış olabilecek bir nesneyi döndürüyor. Bu yüzden ilk değer trueönbelleğe alındı ​​- ve ikinci değer döndürüyor false- 128 önbelleğe alınmış bir değer değil, bu nedenle iki ayrı Integerörnek alıyorsunuz .

Bu notu için önemlidir Birlikte başvuruları karşılaştırarak olduğunu Integer#valueOfve ne önbellek desteklerden daha büyük bir değer karşılaştırdığınız, o olacak değil değerlendirmek trueçözümlenen değerler eşdeğer olsa bile (noktada durum: Integer.valueOf(128) == Integer.valueOf(128)). Sen gerekir kullanmak equals()yerine.

parseIntbir ilkel geri dönüyor int. Bu nedenle üçüncü değer geri döner true- 128 == 128değerlendirilir ve elbette true.

Şimdi, üçüncü sonucu elde etmek için adil bir şey olur true:

  • Bir kutudan çıkarma dönüşüm oluşur yani - kullandığınız denklik operatörü ve sahip veri türleri açısından intve Integer. Bir alıyoruz Integergelen valueOftabii ki, sağ tarafta.

  • Dönüşümden sonra, iki ilkel intdeğeri karşılaştırıyorsunuz . Karşılaştırma, ilkellerle ilgili olarak beklediğiniz gibi gerçekleşir, bu yüzden karşılaştırma 128ve 128.


2
@ user3152527: Büyük bir fark var - biri nesne olarak kabul edilir, yani yöntemleri çağırabilir ve onun gibi soyut veri yapılarında etkileşime girebilirsiniz List. Diğeri ilkel, sadece ham bir değer.
Makoto

1
@ user3152527 Mükemmel bir soru sordunuz (en kötüsü aptal değil). Ama bunu .equals kullanacak şekilde düzelttin, değil mi?
user2910265

3
Ah, sorgulayıcı Java'da temel bir gerçeği anlamadığı anlaşılıyor: İki nesneyi karşılaştırmak için "==" kullanırken, aynı nesneye başvuru olup olmadığını test ediyorsunuz. "Equals ()" kullanırken, aynı değere sahip olup olmadıklarını test edersiniz. İlkelleri karşılaştırmak için "eşittir" i kullanamazsınız.
Jay

3
@ Hayır, anlıyorum. ama ilk başta beni şaşırtan şey, birincisinin neden aynı karşılaştırma yöntemini kullanarak doğru, ikincisinin yanlış döndüğüdür ==. neyse, şimdi açık.
DnR

1
Nit: Sadece Tamsayı "-128 ve 127 arasında önbelleğe alınabilir" değildir . JLS 5.1.7'ye göre olması gerekir . Bu aralığın dışında önbelleğe alınabilir , ancak olmak zorunda değildir (ve genellikle yoktur).
yshavit

127

IntegerSınıf depolar 256 özel olduğunu, statik önbellek sahip Integergöz önüne aldığımızda -128 ile 127 arasında her değeri için bir, bu üç arasındaki farkı düşünün - nesneler.

new Integer(123);

Bu (açıkça) yepyeni bir Integernesne yapar .

Integer.parseInt("123");

Bu ,. intAyrıştırıldıktan sonra ilkel bir değer döndürür String.

Integer.valueOf("123");

Bu diğerlerinden daha karmaşık. İle ayrıştırılır String. Sonra, değer -128 ile 127 arasındaysa, karşılık gelen nesneyi statik önbellekten döndürür. Değer bu aralığın dışındaysa, new Integer()yeni bir nesne elde etmek için değeri çağırır ve iletir .

Şimdi, sorudaki üç ifadeyi düşünün.

Integer.valueOf("127")==Integer.valueOf("127");

IntegerDeğeri 127 olan statik önbellekten iki kez alındığı ve kendisiyle karşılaştırıldığı için bu doğru döner . Integerİlgili tek bir nesne var, bu yüzden geri dönüyor true.

Integer.valueOf("128")==Integer.valueOf("128");

false128 statik önbellekte olmadığı için bu geri döner . Böylece Integereşitliğin her iki tarafı için yeni bir yaratıldı. İki farklı Integernesne olduğundan ve ==nesneler için yalnızca trueher iki tarafın da aynı nesne olması durumunda geri döner , bu olur false.

Integer.parseInt("128")==Integer.valueOf("128");

Bu, intsoldaki ilkel değeri 128, sağda yeni oluşturulan bir Integernesne ile karşılaştırmaktadır. Bir karşılaştırma mantıklı değil çünkü Ama intbir etmek IntegerJava otomatik Unbox olacak Integerkarşılaştırma yapmadan önce; böylece bir intile bir karşılaştırırsınız int. İlkel 128 kendisine eşit olduğu için bu geri döner true.


13

Bu yöntemlerden değer döndürmeye özen gösterin. ValueOf yöntemi, bir tamsayı örneğini verir:

public static Integer valueOf(int i)

ParseInt değeri (basit tür) tamsayı yöntemi döndürür:

public static int parseInt(String s) throws NumberFormatException

Karşılaştırma için açıklama:

Belleği kaydetmek için, sarıcı nesnelerinin iki örneği, ilkel değerleri aynı olduğunda her zaman == olur:

  • Boole
  • Bayt
  • \ U0000 - \ u007f arası karakter (7f ondalık olarak 127'dir)
  • Kısa ve Tam Sayı -128'den 127'ye

Bir ilkel ile bir sargıyı karşılaştırmak için == kullanıldığında, sargı paketinden çıkarılır ve karşılaştırma ilkel ile ilkel olur.

Durumunuzda (yukarıdaki kurallara göre):

Integer.valueOf("127")==Integer.valueOf("127")

Bu ifade, -128 ile 127 arasında Tamsayı değeri içerdiğinden, aynı nesneye başvuruları karşılaştırır, böylece geri döner true.

Integer.valueOf("128")==Integer.valueOf("128")

Bu ifade, <-128, 127> 'de olmayan Tamsayı değerleri içerdiğinden farklı nesnelere başvuruları karşılaştırır, böylece geri döner false.

Integer.parseInt("128")==Integer.valueOf("128")

Bu ifade, ilkel değeri (sol taraf) ve nesneye referansı (sağ taraf) karşılaştırır, böylece sağ taraf sargısız olur ve ilkel türü sol ile karşılaştırılır, böylece geri döner true.



Teklif kaynağı için bir URL sağlayabilir misiniz?
Philzen

"... sarıcı nesnelerin iki örneği, ilkel değerleri aynı olduğunda her zaman == olur ..." - kesinlikle yanlış. Aynı değere sahip iki sarıcı nesne oluşturursanız ==, farklı nesneler olduklarından, bu değerlerle karşılaştırıldığında true döndürmezler .
Dawood ibn Kareem

6

Tamsayı nesneleri 256 Tamsayının -128 ile 127 arasında önbelleğe alınır

Nesne başvurularını == veya ! = İle karşılaştırmamalısınız . Kullanmalısın . eşittir (..) veya daha iyisi - Tamsayı yerine ilkel int kullanın.

parseInt : Dize bağımsız değişkenini işaretli ondalık tam sayı olarak ayrıştırır. Dizedeki karakterlerin tümü ondalık basamak olmalıdır, ancak ilk karakter negatif bir değeri belirtmek için ASCII eksi işareti '-' ('\ u002D') olabilir. Sonuçta elde edilen tam sayı değeri, tıpkı argüman ve sayı tabanı 10, parseInt (java.lang.String, int) yöntemine bağımsız değişken olarak verilmiş gibi döndürülür.

valueOf İkinci bağımsız değişken tarafından verilen yarıçapla ayrıştırıldığında belirtilen Dizeden çıkarılan değeri tutan bir Tamsayı nesnesi döndürür. İlk argüman, tıpkı argümanlar parseInt (java.lang.String, int) yöntemine verilmiş gibi, ikinci argüman tarafından belirtilen yarıçaptaki işaretli bir tamsayıyı temsil ettiği şeklinde yorumlanır. Sonuç, dize tarafından belirtilen tamsayı değerini temsil eden bir Tamsayı nesnesidir.

eşittir

new Integer(Integer.parseInt(s, radix))

sayı tabanı - yorumlamada kullanılacak sayı tabanı

eğer Integer.valueOf()aradaki tamsayıya eşit olursanız

-128 ila 127 sizin durumunuzda doğru döner

için lesser than-128 ve greater than127 o verirfalse


6

Verilen cevapları tamamlamak için aşağıdakilere de dikkat edin:

public class Test { 
    public static void main(String... args) { 
        Integer a = new Integer(129);
        Integer b = new Integer(129);
        System.out.println(a == b);
    }
}

Bu kod ayrıca yazdırılacaktır: false

Jay kullanıcısı , kabul edilen cevap için bir yorumda iddia ettiği gibi, operatörü ==nesneler üzerinde kullanırken dikkatli olunmalıdır , burada her iki referansın da aynı olup olmadığını kontrol ediyorsunuz, aynı değer. Nesneleri karşılaştırmak için equals bunun yerine yöntemi kullanmalısınız:

Integer a = new Integer(128);
Integer b = new Integer(128);
System.out.println(a.equals(b));

Bu yazdırılacak: true

Siz sorabilirsiniz, Ama neden ilk satır basıldı true? . Integer.valueOfYöntemin kaynak kodunu kontrol ederek aşağıdakileri görebilirsiniz:

public static Integer valueOf(String s) throws NumberFormatException {
    return Integer.valueOf(parseInt(s, 10));
}

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

Param IntegerCache.low(varsayılan olarak -128 olarak ayarlanmıştır) ile IntegerCache.high(çalışma zamanında minimum 127 değeri ile hesaplanır ) arasında bir tamsayı ise, önceden ayrılmış (önbelleğe alınmış) bir nesne döndürülür. Parametre olarak 127 kullandığınızda, aynı önbelleğe alınmış nesneye iki referans alırsınız trueve referansları karşılaştırırsınız.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.