Saya tahu bahwa jika Anda membandingkan bilangan bulat primitif kotak dengan konstanta seperti:
Integer a = 4;
if (a < 5)
a
secara otomatis akan dihapus dari kotak dan perbandingan akan berfungsi.
Namun, apa yang terjadi ketika Anda membandingkan dua kotak Integers
dan ingin membandingkan kesetaraan atau kurang dari / lebih besar dari?
Integer a = 4;
Integer b = 5;
if (a == b)
Akankah kode di atas menghasilkan pengecekan untuk melihat apakah mereka adalah objek yang sama, atau akankah itu dihapus otomatis dalam kasus itu?
Bagaimana dengan:
Integer a = 4;
Integer b = 5;
if (a < b)
?
java
integer
autoboxing
shmosel
sumber
sumber
==
alih-alihequals
menghasilkan hasil yang benar, itu mungkin karena nomor kotak sedang diinternir atau digunakan kembali (sebagai optimasi kompiler, mungkin). Alasan untuk mengajukan pertanyaan ini adalah untuk mencari tahu apa yang terjadi secara internal, bukan apa yang tampaknya terjadi. (Setidaknya, itulah sebabnya saya di sini.)Jawaban:
Tidak, == antara Integer, Long dll akan memeriksa kesetaraan referensi - yaitu
ini akan memeriksa apakah
x
dany
merujuk ke objek yang sama daripada objek yang sama .Begitu
dijamin untuk mencetak
false
. Menginternir nilai "kecil" yang diautobox dapat menyebabkan hasil yang rumit:Ini akan dicetak
true
, karena aturan tinju ( JLS bagian 5.1.7 ). Itu masih referensi kesetaraan yang digunakan, tetapi referensi itu benar - benar sama.Secara pribadi saya akan menggunakan:
atau
Seperti yang Anda katakan, untuk perbandingan apa pun antara jenis pembungkus (
Integer
,Long
dll) dan jenis numerik (int
,long
dll) nilai jenis pembungkusnya adalah tanpa kotak dan tes diterapkan pada nilai-nilai primitif yang terlibat.Ini terjadi sebagai bagian dari promosi numerik biner ( JLS bagian 5.6.2 ). Lihatlah dokumentasi masing-masing operator untuk melihat apakah itu diterapkan. Misalnya, dari dokumen untuk
==
dan!=
( JLS 15.21.1 ):dan untuk
<
,<=
,>
dan>=
( JLS 15.20.1 )Perhatikan bagaimana semua ini dianggap sebagai bagian dari situasi di mana tidak ada tipe yang merupakan tipe numerik.
sumber
x.compareTo(y) < 0
alih-alihx < y
?==
masih akan menguji kesetaraan objek. Namun, mudah untuk dibodohi:Contoh Anda dengan ketidaksetaraan akan bekerja karena mereka tidak didefinisikan pada Objek. Namun, dengan
==
perbandingan, kesetaraan objek masih akan diperiksa. Dalam hal ini, ketika Anda menginisialisasi objek dari primitif kotak, objek yang sama digunakan (untuk a dan b). Ini adalah pengoptimalan yang oke karena kelas kotak primitif tidak dapat diubah.sumber
200
, kedua tes akan mencetakfalse
.equals
dipanggil".Karena Java 1.7, Anda dapat menggunakan Objects.equals :
sumber
==
memeriksa persamaan referensi, namun ketika menulis kode seperti:Java cukup pintar untuk menggunakan kembali berubah sama untuk
a
danb
, jadi ini benar:a == b
. Penasaran, saya menulis contoh kecil untuk menunjukkan di mana java berhenti mengoptimalkan dengan cara ini:Ketika saya mengkompilasi dan menjalankan ini (di mesin saya), saya mendapatkan:
sumber
tl; dr pendapat saya adalah menggunakan unary
+
untuk memicu unboxing pada salah satu operan ketika memeriksa kesetaraan nilai, dan cukup gunakan operator matematika sebaliknya. Dasar pemikirannya sebagai berikut:Telah disebutkan bahwa
==
perbandinganInteger
adalah perbandingan identitas, yang biasanya bukan yang diinginkan oleh seorang programmer, dan tujuannya adalah untuk melakukan perbandingan nilai; tetap, saya telah melakukan sedikit ilmu tentang bagaimana melakukan perbandingan itu paling efisien, baik dalam hal kekompakan kode, kebenaran dan kecepatan.Saya menggunakan banyak metode:
dan mendapatkan kode ini setelah kompilasi dan dekompilasi:
Seperti yang dapat Anda lihat dengan mudah, metode 1 memanggil
Integer.equals()
(jelas), metode 2-4 menghasilkan kode yang persis sama , membuka nilai dengan menggunakan.intValue()
dan kemudian membandingkannya secara langsung, dan metode 5 hanya memicu perbandingan identitas, menjadi cara yang salah untuk membandingkan nilai.Karena (seperti yang telah disebutkan oleh JS misalnya)
equals()
menimbulkan overhead (yang harus dilakukaninstanceof
dan pemain yang tidak dicentang), metode 2-4 akan bekerja dengan kecepatan yang sama persis, lebih baik dari metode 1 saat digunakan dalam loop ketat, karena HotSpot tidak kemungkinan untuk mengoptimalkan gips &instanceof
.Ini sangat mirip dengan operator perbandingan lainnya (misalnya
<
/>
) - mereka akan memicu unboxing, sementara menggunakancompareTo()
tidak - tetapi kali ini, operasi ini sangat dioptimalkan oleh HS karenaintValue()
hanya metode pengambil (kandidat utama untuk dioptimalkan keluar).Menurut pendapat saya, versi 4 yang jarang digunakan adalah cara yang paling ringkas - setiap pengembang C / Java berpengalaman tahu bahwa plus unary dalam banyak kasus sama dengan dilemparkan ke
int
/.intValue()
- sementara itu mungkin sedikit momen WTF untuk beberapa (kebanyakan mereka yang tidak dapat menggunakan unary plus dalam masa hidup mereka), ini bisa menunjukkan maksud yang paling jelas dan paling singkat - ini menunjukkan bahwa kita menginginkanint
nilai dari salah satu operan, memaksa nilai lainnya untuk unbox juga. Ini juga sangat mirip dengani1 == i2
perbandingan reguler yang digunakan untukint
nilai-nilai primitif .Pilihan saya berlaku untuk
i1 == +i2
&i1 > i2
gaya untukInteger
objek, baik untuk alasan kinerja & konsistensi. Itu juga membuat kode portabel untuk primitif tanpa mengubah apa pun selain tipe deklarasi. Menggunakan metode bernama sepertinya memperkenalkan kebisingan semantik kepada saya, mirip dengan gaya yang banyak dikritikbigInt.add(10).multiply(-3)
.sumber
unary +
(unary plus), lihat misalnya stackoverflow.com/questions/2624410/...Panggilan
Akan bekerja sebagian besar waktu, tetapi tidak dijamin untuk selalu bekerja, jadi jangan menggunakannya.
Cara paling tepat untuk membandingkan dua kelas Integer untuk kesetaraan, dengan asumsi mereka diberi nama 'a' dan 'b' adalah dengan memanggil:
Anda juga dapat menggunakan cara ini yang sedikit lebih cepat.
Pada mesin saya 99 miliar operasi membutuhkan waktu 47 detik menggunakan metode pertama, dan 46 detik menggunakan metode kedua. Anda harus membandingkan miliaran nilai untuk melihat perbedaan apa pun.
Perhatikan bahwa 'a' mungkin nol karena ini adalah Objek. Membandingkan dengan cara ini tidak akan menyebabkan pengecualian pointer nol.
Untuk membandingkan lebih besar dan lebih sedikit daripada, gunakan
sumber
if (a==b)
hanya berfungsi untuk nilai kecil dan tidak akan berfungsi sebagian besar waktu.Kita harus selalu menggunakan metode equals () untuk perbandingan untuk dua bilangan bulat. Adalah praktik yang disarankan.
Jika kita membandingkan dua bilangan bulat menggunakan == yang akan bekerja untuk rentang nilai integer tertentu (Integer dari -128 ke 127) karena optimasi internal JVM.
Silakan lihat contoh:
Kasus 1:
Dalam kasus di atas JVM menggunakan nilai a dan b dari kolam renang cache dan kembali objek contoh yang sama (karena alamat memori) dari objek integer dan kita mendapatkan keduanya equal.Its sebuah JVM optimasi dilakukan untuk nilai rentang tertentu.
Kasus 2: Dalam kasus ini, a dan b tidak sama karena tidak datang dengan kisaran -128 hingga 127.
Cara yang tepat:
Saya harap ini membantu.
sumber
Dalam kasus saya, saya harus membandingkan dua
Integer
untuk persamaan di mana keduanya bisanull
. Mencari topik serupa, tidak menemukan sesuatu yang elegan untuk ini. Muncul dengan fungsi utilitas sederhana.sumber
Karena metode perbandingan harus dilakukan berdasarkan tipe int (x == y) atau kelas Integer (x.equals (y)) dengan operator yang tepat
sumber
metode ini membandingkan dua Integer dengan cek kosong, lihat tes
sumber
Objects.equals(x,y)
metode daripada menggulung sendiri.