Java: Tamsayı eşittir ==


152

Java 1.5 itibariyle hemen hemen alışverişini can Integerile intbirçok durumda.

Ancak, kodumda beni biraz şaşırtan potansiyel bir kusur buldum.

Aşağıdaki kod:

Integer cdiCt = ...;
Integer cdsCt = ...;
...
if (cdiCt != null && cdsCt != null && cdiCt != cdsCt)
    mismatch = true;

hangi şartlar altında belirleyemesem de, değerler eşit olduğunda yanlış eşleşmemesi gibi görünüyordu. Eclipse'de bir kesme noktası belirledim ve Integerdeğerlerin her ikisi de 137 olduğunu gördüm ve boole ifadesini inceledim ve bunun yanlış olduğunu söyledi, ancak üzerine bastığımda uyumsuzluğu true olarak ayarlıyordu.

Şartlı şunun değiştirilmesi:

if (cdiCt != null && cdsCt != null && !cdiCt.equals(cdsCt))

sorunu çözdü.

Bunun neden olduğuna kimse ışık tutabilir mi? Şimdiye kadar, localhost'umdaki davranışı sadece kendi bilgisayarımda gördüm. Bu özel durumda, kod başarılı bir şekilde yaklaşık 20 karşılaştırmayı geçmiş, ancak 2'de başarısız olmuştur. Sorun sürekli olarak yeniden oluşturulabilirdi.

Yaygın bir sorunsa, diğer ortamlarımızda (dev ve test) hatalara neden olmalı, ancak şu ana kadar bu kod snippet'ini yürüten yüzlerce testten sonra kimse sorunu bildirmedi.

==İki Integerdeğeri karşılaştırmak için hala meşru değil mi?

Aşağıdaki tüm iyi cevaplara ek olarak, aşağıdaki stackoverflow bağlantısı biraz ek bilgiye sahiptir. Aslında asıl sorumu yanıtlardı, ama sorumda otomatik bokstan bahsetmediğim için, seçilen önerilerde görünmedi:

Derleyici / JVM neden otomatik boksu “sadece işe yaramaz”?

Yanıtlar:


238

JVM, Tamsayı değerlerini önbelleğe alıyor. == yalnızca -128 ile 127 arasındaki sayılar için çalışır http://www.owasp.org/index.php/Java_gotchas#Immutable_Objects_.2F_Wrapper_Class_Caching


1
Teşekkürler, bu kesinlikle neden 137 başarısız olduğunu açıklıyor! Ve aynı zamanda neden yaygın bir sorun olmadığına dair soruma cevap veriyor, karşılaşacağım vakaların% 95'inde değer 127'nin altında olacak. Şimdi bunu yakalamak için iyi değil.
Jeremy Goodell

1
İlginç yan not: birkaç hafta öncesine kadar, cdiCt ve cdsCt her ikisi de ints idi, bu yüzden bu iyiydi, ama farklı işlenen boş durumu kontrol etmek için onları Tamsayı yapmak zorunda kaldım ...
Jeremy Goodell

3
@Jeremy Evet, bu oldukça belirsiz bir sorundur, ancak genel bir kural olarak Nesneler için .equals () ve ilkel öğeler için == kullanırsınız. Eşitlik testi için otomatik kutulamaya güvenemezsiniz.
Adam

1
Lol, onay işareti sana geri döndü! Görünüşe göre Colin zaten yeterince fazla noktaya sahip.
Jeremy Goodell

2
Yeni Tamsayı (1)! = Yeni Tamsayı (1) 'in de olduğunu unutmayın. yeni DAİMA yeni bir adres döndürür. Otomatik boks önbelleğe alınmış bir sürüm kullanır. Tamsayıları döndüren diğer yollar (onları yenileştirmeden) büyük olasılıkla önbelleğe alınan değeri de döndürür.
Bill K

77

İkisini Integerbasit bir ==nesne ile karşılaştıramazsınız , bu nedenle çoğu zaman referanslar aynı olmaz.

Integer-128 ve 127 arasında bir hile var , referanslar Integer.valueOf()küçük tam sayıları önbelleğe alan otomatik boks kullanımlarıyla aynı olacaktır .

Kutulu p değeri doğru, yanlış, bir bayt, \ u0000 ila \ u007f aralığındaki bir karakter veya -128 ile 127 arasında bir int veya kısa sayı ise, r1 ve r2 iki boks dönüşümünün sonucu olsun s. Her zaman r1 == r2 söz konusudur.


Kaynaklar:

Aynı konuda:


1
JLS'nin garantisi mi yoksa sadece Oracle JVM için mi?
Thorbjørn Ravn Andersen

Alıntılanan kısım JLS'den, bu yüzden JLS
Colin Hebert'in

Re: garanti. Hala buna çok fazla güvenmem. new Integer(1) == new Integer(1)hala yanlış.
Thilo

@Thilo new ... == new ...her zaman false.
MC İmparatoru

2
@Thilo True, her equals()zaman nesnelerle uğraşırken kullanın . Java öğrenirken bilmeniz gereken ilk şeylerden biri bu olmalıdır. Bu arada, kurucusunun Integerözel olduğunu, yani örneklerin her zaman valueOf()yöntemle yaratıldığını tahmin ederdim . Ama kurucunun halka açık olduğunu görüyorum.
MC İmparatoru

5

Sorun şu ki, iki Tamsayı nesneniz sadece nesnelerdir. Eşleşmezler çünkü içindeki iki nesne referansını karşılaştırırsınız, içindeki değerleri değil. Açıkçası .equals, bir nesne referans karşılaştırmasının aksine bir değer karşılaştırması sağlamak için geçersiz kılınır.


Güzel cevap, ama neden sadece 137 için başarısız olduğunu açıklamıyor.
Jeremy Goodell

4

Integerreferansı, yani karşılaştırdığınız referansları karşılaştırırken değeri değil aynı nesneyi gösterip göstermediklerini belirtir. Bu nedenle, gördüğünüz sorun. Düz inttürlerle bu kadar iyi çalışmasının nedeni Integer,.

Yaptığınız şeyi yapıyorsanız, neden bu ififadeyle başlayacağınızı ekleyebilir miyim ?

mismatch = ( cdiCt != null && cdsCt != null && !cdiCt.equals( cdsCt ) );

4

"==" her zaman değerlerin bellek konumunu veya nesne başvurularını karşılaştırır. eşittir yöntemi her zaman değerleri karşılaştırır. Ancak eşittir, değerleri karşılaştırmak için dolaylı olarak "==" operatörünü de kullanır.

Tamsayı, -128 ile +127 arasındaki değerleri saklamak için Tamsayı önbelleğini kullanır. == operatörü -128 ila 127 arasında herhangi bir değeri kontrol etmek için kullanılırsa true değerini döndürür. bu değerler dışındaki değerler için false değerini döndürür.

Bakın Bazı ek bilgiler bağlantıya


1

Kullanımın doğruluğu için ==, karşılaştırma Integeryapmadan önce karşılaştırılan değerlerden birinin kutusunu kaldırabilirsiniz ==, örneğin:

if ( firstInteger.intValue() == secondInteger ) {..

İkincisi otomatik olarak kutudan çıkarılır (elbette nullönce s'yi kontrol etmeniz gerekir ).


0

Bu büyük cevapların yanı sıra, öğrendiklerim:

Referanslarıyla karşılaştırmak istemiyorsanız ASLA == ile nesneleri karşılaştırmayın.

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.