Java: Integer sama dengan vs ==


152

Pada Java 1.5, Anda dapat cukup banyak interchange Integerdengan intdalam banyak situasi.

Namun, saya menemukan cacat potensial dalam kode saya yang sedikit mengejutkan saya.

Kode berikut:

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

tampaknya salah mengatur ketidakcocokan ketika nilainya sama, meskipun saya tidak bisa menentukan dalam keadaan apa. Saya menetapkan breakpoint di Eclipse dan melihat bahwa Integernilai keduanya 137, dan saya memeriksa ekspresi boolean dan mengatakan itu salah, tetapi ketika saya melangkahinya, itu membuat ketidakcocokan menjadi kenyataan.

Mengubah persyaratan ke:

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

memperbaiki masalah.

Adakah yang bisa menjelaskan mengapa ini terjadi? Sejauh ini, saya hanya melihat perilaku di localhost saya di PC saya sendiri. Dalam kasus khusus ini, kode berhasil melewati sekitar 20 perbandingan, tetapi gagal pada 2. Masalahnya secara konsisten dapat direproduksi.

Jika itu adalah masalah yang lazim, itu harus menyebabkan kesalahan pada lingkungan kami yang lain (dev dan pengujian), tetapi sejauh ini, tidak ada yang melaporkan masalah setelah ratusan tes yang mengeksekusi cuplikan kode ini.

Apakah masih tidak sah untuk digunakan ==untuk membandingkan dua Integernilai?

Selain semua jawaban bagus di bawah ini, tautan stackoverflow berikut memiliki sedikit informasi tambahan. Itu sebenarnya akan menjawab pertanyaan awal saya, tetapi karena saya tidak menyebutkan autoboxing dalam pertanyaan saya, itu tidak muncul dalam saran yang dipilih:

Mengapa kompiler / JVM tidak bisa membuat autoboxing “hanya berfungsi”?

Jawaban:


238

JVM adalah caching nilai Integer. == hanya berfungsi untuk angka antara -128 dan 127 http://www.owasp.org/index.php/Java_gotchas#Immutable_Objects_.2F_Wrapper_Class_Caching


1
Terima kasih, itu jelas menjelaskan mengapa 137 gagal! Dan itu juga menjawab pertanyaan saya tentang mengapa itu bukan masalah yang lazim, dalam 95% kasus yang akan saya temui, nilainya akan di bawah 127. Baik untuk menangkap ini sekarang meskipun untuk 5% di mana tidak.
Jeremy Goodell

1
Catatan menarik: sampai beberapa minggu yang lalu, cdiCt dan cdsCt sama-sama int jadi ini baik-baik saja, tetapi saya harus membuatnya bilangan bulat untuk memeriksa situasi nol yang ditangani secara berbeda ...
Jeremy Goodell

3
@ Jeremy Ya, ini masalah yang cukup tidak jelas, tetapi sebagai aturan umum Anda menggunakan .equals () untuk Objects dan == untuk primitif. Anda tidak dapat mengandalkan autounboxing untuk pengujian kesetaraan.
Adam

1
Lol, centang tanda kembali kepada Anda kalau begitu! Sepertinya Colin sudah memiliki poin lebih dari cukup.
Jeremy Goodell

2
Perhatikan bahwa Integer baru (1)! = Integer baru (1) juga. SELALU baru mengembalikan alamat baru. Autoboxing menggunakan versi cache. Cara lain yang mengembalikan Integer (tanpa memperbaruinya) mungkin mengembalikan nilai yang di-cache juga.
Bill K

77

Anda tidak dapat membandingkan dua Integerdengan objek yang sederhana ==sehingga sebagian besar referensi waktu tidak akan sama.

Ada trik, dengan Integerantara -128 dan 127, referensi akan sama dengan penggunaan autoboxing Integer.valueOf()yang menyimpan bilangan bulat kecil.

Jika nilai p yang dikotakkan adalah benar, salah, satu byte, karakter dalam kisaran \ u0000 hingga \ u007f, atau int atau angka pendek antara -128 dan 127, maka biarkan r1 dan r2 menjadi hasil dari dua konversi tinju dari hal. Itu selalu terjadi bahwa r1 == r2.


Sumber:

Pada topik yang sama:


1
Apakah jaminan dari JLS atau hanya untuk Oracle JVM?
Thorbjørn Ravn Andersen

Bagian yang dikutip dari JLS, jadi itu jaminan dari JLS
Colin Hebert

Re: jaminan. Saya masih tidak akan terlalu bergantung pada itu. new Integer(1) == new Integer(1)masih salah.
Thilo

@Thilo new ... == new ...selalu false.
MC Kaisar

2
@Thilo Benar, selalu gunakan equals()saat berhadapan dengan objek. Ini harus menjadi salah satu hal pertama yang harus diketahui ketika belajar Java. Ngomong-ngomong, saya akan menduga bahwa konstruktor Integeritu pribadi, yaitu bahwa instance selalu dibuat melalui valueOf()metode. Tetapi saya melihat bahwa konstruktornya bersifat publik.
MC Kaisar

5

Masalahnya adalah bahwa dua objek Integer Anda hanya itu, objek. Mereka tidak cocok karena Anda membandingkan dua referensi objek Anda, bukan nilai-nilai di dalamnya. Jelas .equalsdiganti untuk memberikan perbandingan nilai yang bertentangan dengan perbandingan referensi objek.


Jawaban yang bagus, tetapi itu tidak menjelaskan mengapa ini hanya gagal untuk 137.
Jeremy Goodell

4

Integermerujuk pada referensi, yaitu, ketika membandingkan referensi yang Anda bandingkan jika mereka menunjuk ke objek yang sama, bukan nilai. Oleh karena itu, masalah yang Anda lihat. Alasan itu bekerja sangat baik dengan inttipe polos adalah bahwa itu membuka kotak nilai yang terkandung oleh Integer.

Bolehkah saya menambahkan bahwa jika Anda melakukan apa yang Anda lakukan, mengapa harus memiliki ifpernyataan itu?

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

4

"==" selalu membandingkan lokasi memori atau referensi objek dari nilai. sama dengan metode selalu membandingkan nilai. Tetapi equals juga secara tidak langsung menggunakan operator "==" untuk membandingkan nilai.

Integer menggunakan cache Integer untuk menyimpan nilai dari -128 hingga +127. Jika == operator digunakan untuk memeriksa nilai apa pun antara -128 hingga 127 maka itu mengembalikan nilai true. untuk selain nilai-nilai ini mengembalikan false.

Lihat tautan untuk beberapa info tambahan


1

Selain itu untuk kebenaran penggunaan, ==Anda dapat mencopot salah satu Integernilai yang dibandingkan sebelum melakukan ==perbandingan, seperti:

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

Yang kedua akan otomatis terbuka (tentu saja Anda harus memeriksa nulldulu).


0

Selain jawaban-jawaban luar biasa ini, Yang saya pelajari adalah:

JANGAN PERNAH membandingkan objek dengan == kecuali Anda bermaksud membandingkannya dengan referensi mereka.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.