Saya baru saja melihat kode yang mirip dengan ini:
public class Scratch
{
public static void main(String[] args)
{
Integer a = 1000, b = 1000;
System.out.println(a == b);
Integer c = 100, d = 100;
System.out.println(c == d);
}
}
Saat dijalankan, blok kode ini akan dicetak:
false
true
Saya mengerti mengapa yang pertama adalah false
: karena kedua objek tersebut adalah objek yang terpisah, jadi ==
membandingkan referensi. Tapi saya tidak tahu, mengapa pernyataan kedua kembali true
? Apakah ada aturan autoboxing aneh yang berlaku saat nilai Integer berada dalam kisaran tertentu? Apa yang terjadi di sini?
java
autoboxing
Joel
sumber
sumber
Jawaban:
The
true
garis sebenarnya dijamin oleh spesifikasi bahasa. Dari bagian 5.1.7 :Diskusi berlanjut, menunjukkan bahwa meskipun baris kedua keluaran Anda dijamin, yang pertama tidak (lihat paragraf terakhir yang dikutip di bawah):
sumber
valueOf
metode kelas kotak (sepertiInteger.valueOf(int)
). Menarik bahwa JLS mendefinisikan desugaring unboxing yang tepat - menggunakanintValue()
dkk - tetapi bukan desugaring tinju.Integer
selain melaluipublic
API resmi , yaitu dengan meneleponintValue()
. Tetapi ada cara lain yang mungkin untuk mendapatkan sebuahInteger
instance untuk suatuint
nilai, misalnya kompiler dapat menghasilkan penyimpanan kode dan menggunakan kembaliInteger
instance yang dibuat sebelumnya .Keluaran:
Ya, keluaran pertama diproduksi untuk membandingkan referensi; 'a' dan 'b' - ini adalah dua referensi yang berbeda. Pada poin 1, sebenarnya dibuat dua referensi yang mirip dengan -
Keluaran kedua dihasilkan karena
JVM
mencoba untuk menghemat memori, ketikaInteger
berada dalam kisaran (dari -128 hingga 127). Pada poin 2 tidak ada referensi baru untuk tipe Integer dibuat untuk 'd'. Alih-alih membuat objek baru untuk variabel referensi tipe Integer 'd', itu hanya ditugaskan dengan objek yang dibuat sebelumnya direferensikan oleh 'c'. Semua ini dilakukan olehJVM
.Aturan penyimpanan memori ini tidak hanya untuk Integer. untuk tujuan penyimpanan memori, dua contoh objek pembungkus berikut (saat dibuat melalui tinju), akan selalu == di mana nilai primitifnya sama -
\u007f
(7f adalah 127 dalam desimal)sumber
Long
juga memiliki cache dengan kisaran yang sama sepertiInteger
.Objek bilangan bulat dalam beberapa kisaran (saya pikir mungkin -128 hingga 127) di-cache dan digunakan kembali. Bilangan bulat di luar rentang tersebut mendapatkan objek baru setiap kali.
sumber
java.lang.Integer.IntegerCache.high
properti. Menarik bahwa Long tidak memiliki opsi itu.Ya, ada aturan autoboxing aneh yang berlaku saat nilai berada dalam kisaran tertentu. Saat Anda menetapkan konstanta ke variabel Objek, tidak ada dalam definisi bahasa yang mengatakan objek baru harus dibuat. Ini dapat menggunakan kembali objek yang ada dari cache.
Faktanya, JVM biasanya akan menyimpan cache dari Integer kecil untuk tujuan ini, serta nilai-nilai seperti Boolean.TRUE dan Boolean.FALSE.
sumber
Dugaan saya adalah bahwa Java menyimpan cache bilangan bulat kecil yang sudah 'dikotak' karena sangat umum dan menghemat banyak waktu untuk menggunakan kembali objek yang ada daripada membuat yang baru.
sumber
Itu adalah hal yang menarik. Dalam buku Java Efektif menyarankan untuk selalu menimpa sama dengan kelas Anda sendiri. Juga, untuk memeriksa kesetaraan untuk dua contoh objek dari kelas java selalu gunakan metode sama.
kembali:
sumber
Di Java tinju bekerja dalam kisaran antara -128 dan 127 untuk Integer. Saat Anda menggunakan angka dalam rentang ini, Anda dapat membandingkannya dengan operator ==. Untuk objek Integer di luar rentang Anda harus menggunakan sama.
sumber
Penetapan langsung literal int ke referensi Integer adalah contoh auto-boxing, di mana nilai literal ke kode konversi objek ditangani oleh kompilator.
Jadi selama fase kompilasi, kompilator diubah
Integer a = 1000, b = 1000;
menjadiInteger a = Integer.valueOf(1000), b = Integer.valueOf(1000);
.Jadi ini adalah
Integer.valueOf()
metode yang benar-benar memberi kita objek integer, dan jika kita melihat kode sumberInteger.valueOf()
metode kita dapat dengan jelas melihat metode cache objek integer dalam kisaran -128 hingga 127 (inklusif).Jadi, alih-alih membuat dan mengembalikan objek integer baru,
Integer.valueOf()
metode ini mengembalikan objek Integer dari internalIntegerCache
jika literal int yang diteruskan lebih besar dari -128 dan kurang dari 127.Java menyimpan cache objek integer ini karena kisaran integer ini banyak digunakan dalam pemrograman sehari-hari yang secara tidak langsung menghemat beberapa memori.
Cache diinisialisasi pada penggunaan pertama saat kelas dimuat ke memori karena blok statis. Kisaran maksimal cache dapat dikontrol dengan
-XX:AutoBoxCacheMax
opsi JVM.Perilaku caching ini tidak berlaku untuk objek Integer saja, mirip dengan Integer.IntegerCache yang juga kami miliki
ByteCache, ShortCache, LongCache, CharacterCache
untukByte, Short, Long, Character
masing - masing.Anda dapat membaca lebih lanjut di artikel saya Java Integer Cache - Why Integer.valueOf (127) == Integer.valueOf (127) Is True .
sumber
Di Java 5, fitur baru diperkenalkan untuk menghemat memori dan meningkatkan kinerja penanganan objek tipe Integer. Objek integer di-cache secara internal dan digunakan kembali melalui objek referensi yang sama.
Ini berlaku untuk nilai Integer dalam rentang antara –127 hingga +127 (Nilai Integer Maks).
Caching Integer ini hanya berfungsi pada autoboxing. Objek integer tidak akan di-cache saat dibuat menggunakan konstruktor.
Untuk detail lebih lanjut, silakan buka Tautan di bawah ini:
Cache Integer secara Detail
sumber
Jika kita memeriksa kode sumber
Integer
objek, kita akan menemukan sumbervalueOf
metode seperti ini:yang bisa menjelaskan mengapa
Integer
objek, yang dalam rentang dari -128 (Integer.low
) hingga 127 (Integer.high
), adalah objek referensi yang sama selama autoboxing. Dan kita bisa melihat ada kelas yangIntegerCache
menanganiInteger
array cache, yang merupakan kelas dalam kelas statis pribadiInteger
.Ada contoh menarik lainnya yang dapat membantu kita memahami situasi aneh ini:
sumber