Dalam artikel ini, penulis akan memperkenalkan kepada Anda fitur yang sangat penting dan menarik di Java, yang merupakan tinju otomatis dan unboxing, dan menafsirkan prinsip -prinsip tinju otomatis dan unboxing dari kode sumber. Pada saat yang sama, fitur ini juga meninggalkan jebakan. Jika pengembang tidak memperhatikan, mereka akan dengan mudah jatuh ke dalam perangkap ini.
Autoboxing
definisi
Saat menulis program Java, orang sering mendefinisikan objek integer dengan cara berikut:
Integer I = 100;
Dari kode di atas, Anda dapat mengetahui bahwa saya adalah referensi tipe integer dan 100 adalah tipe data dasar di java (tipe data primitif). Metode ini secara langsung melewati tipe data dasar ke kelas pembungkusnya yang sesuai adalah tinju otomatis.
Di JDK 1.5, tinju otomatis diperkenalkan untuk pertama kalinya. Sebelum JDK 1.5, jika Anda ingin mendefinisikan objek integer dengan nilai 100, Anda perlu melakukan ini:
Integer i = bilangan bulat baru (100);
prinsip
Mari kita buat breakpoint pada kode di atas "Integer I = 100;" dan ikuti.
Selanjutnya, kita dapat melihat bahwa program melompat ke metode (int i) metode kelas integer.
/** * Mengembalikan contoh <tt> integer </tt> yang mewakili nilai * <tt> int </tt> yang ditentukan. * Jika instance <tt> integer </tt> baru tidak diperlukan, metode ini * umumnya harus digunakan dalam preferensi untuk konstruktor * {@link #integer (int)}, karena metode ini cenderung menghasilkan * ruang ruang dan waktu yang jauh lebih baik dengan caching * Nilai yang sering diminta. * * @param I nilai <code> int </code>. * @return a <tt> integer </tt> instance mewakili <tt> i </tt>. * @since 1.5 */ Nilai integer statis publik (int i) {if (i> = -128 && i <= integercache.high) return integercache.cache [i + 128]; lain mengembalikan bilangan bulat baru (i); }Dengan kata lain, pengemasan adalah JDK yang membantu Anda menyelesaikan panggilan ke Integer.valueof (100).
Membuka kemasan
definisi
Integer integer100 = 100; int int100 = integer100;
Dari kode di atas, Anda dapat melihat bahwa Integer100 adalah referensi untuk mengetik integer, dan INT100 adalah tipe data primitif tipe int. Namun, kami dapat menetapkan objek tipe integer ke variabel tipe data aslinya yang sesuai. Ini unboxing.
Unboxing adalah kebalikan dari pengemasan. Tinju adalah variabel yang memberikan tipe data primitif ke kelas enkapsulasi yang sesuai. Unboxing berarti menetapkan variabel kelas yang dienkapsulasi ke variabel dari tipe data asli yang sesuai. Nama -nama pengepakan dan unboxing juga cukup tepat.
prinsip
Saya percaya semua orang telah menebak apa yang JDK lakukan untuk kami selama proses unboxing. Mari kita buktikan dugaan kita melalui eksperimen.
Tetapkan breakpoint pada baris kedua dari kode di atas, yaitu, atur breakpoint pada "int int100 = integer100;" dan ikuti.
Kita dapat melihat bahwa program melompat ke metode Integer's IntValue ().
/** * Mengembalikan nilai <code> integer </code> ini sebagai * <code> int </code>. */ public int intvalue () {nilai pengembalian; }Artinya, JDK membantu kami menyelesaikan panggilan ke metode intvalue (). Untuk percobaan di atas, ini adalah untuk memanggil metode integer integer100 dan menetapkan nilai pengembaliannya ke INT100.
Diperpanjang
Eksperimen 1
Integer Integer400 = 400; int int400 = 400; System.out.println (integer400 == int400);
Di baris ketiga dari kode di atas, Integer400 dan Int400 menjalankan run ==. Dan keduanya adalah jenis variabel yang berbeda. Apakah Integer400 Unboxing atau Int400 Packing? Apa hasil operasi?
== Operasi adalah untuk menentukan apakah alamat dua objek sama atau apakah nilai dari dua tipe data dasar sama. Oleh karena itu, mudah untuk menyimpulkan bahwa jika Integer400 tidak terkotak, itu berarti bahwa nilai -nilai dari dua tipe dasar dibandingkan, dan hasil berjalan harus benar pada saat ini; Jika INT400 dikemas, itu berarti bahwa alamat kedua objek itu sama, dan hasil berjalan harus salah saat ini. (Mengenai mengapa penulis menugaskan mereka ke 400, itu terkait dengan perangkap yang akan dibahas nanti).
Hasil lari kami yang sebenarnya adalah benar. Jadi itu adalah Integer400 Unboxing. Hasil pelacakan kode membuktikan ini.
Eksperimen 2
Integer Integer100 = 100; int int100 = 100; System.out.println (integer100.equals (int100));
Pada baris ketiga dari kode di atas, parameter metode Integer100 sama dengan INT100. Kita tahu bahwa parameter metode yang sama adalah objek, bukan tipe data dasar, jadi di sini harus dikemas int100. Hasil pelacakan kode membuktikan ini.
Bahkan, jika jenis parameter dalam metode adalah tipe data asli dan tipe parameter yang dilewati adalah kelas enkapsulasi, itu akan secara otomatis tidak dikotori; Dengan demikian, jika jenis parameter dalam metode adalah jenis enkapsulasi dan jenis parameter yang dilewati adalah tipe data aslinya, itu akan secara otomatis kotak.
Eksperimen 3
Integer Integer100 = 100; int int100 = 100; long long200 = 200l; System.out.println (integer100 + int100); System.out.println (long200 == (integer100 + int100)); System.println (long200.equals (integer100 + integer100 +);
Dalam percobaan pertama, kami telah belajar bahwa ketika tipe data dasar melakukan operasi == operasi dengan kelas enkapsulasi, kelas enkapsulasi akan dibatalkan. Bagaimana jika +, -, *, /? Kita bisa tahu dalam percobaan ini.
Jika + operasi, tipe data yang mendasarinya akan dikotak, maka:
• dalam baris 4, integer100+int100 akan mendapatkan objek o tipe integer dan nilai 200, dan menjalankan metode tostring () dari objek ini dan output "200";
• Dalam baris 5, integer100+int100 akan mendapatkan objek o tipe integer dan nilai 200. Operasi == membandingkan objek ini dengan objek Long200. Jelas, salah akan menjadi output;
• Dalam baris 6, integer100+int100 akan mendapatkan objek o tipe integer dan nilai 200. metode equals long membandingkan long200 dengan o, karena keduanya adalah kelas yang dienkapsulasi dari berbagai jenis, sehingga outputnya salah;
Jika + operasi, kelas enkapsulasi akan unboxed, maka:
• Dalam baris 4, integer100+int100 akan mendapatkan tipe data dasar b tipe int dan nilai 200, lalu kotak b untuk mendapatkan o, menjalankan metode tostring () dari objek ini, dan output "200";
• Dalam baris 5, integer100+int100 akan mendapatkan tipe data dasar b1 tipe int dan nilai 200. Operasi == unbox long200 untuk mendapatkan b2. Jelas B1 == B2, dan output benar;
• Dalam baris 6, integer100+int100 akan mendapatkan tipe data dasar b tipe int dan nilai 200. Long's Equals Metode Box B, tetapi tinju menghasilkan objek o tipe integer, karena O dan Long200 adalah objek dari berbagai jenis, sehingga outputnya salah;
Hasil dari program yang berjalan adalah:
200
BENAR
PALSU
Oleh karena itu, spekulasi kedua adalah benar, yaitu, kelas enkapsulasi akan dibuka selama operasi +.
perangkap
Perangkap 1
Integer integer100 = null;
int int100 = integer100;
Dua baris kode ini sepenuhnya legal dan dapat dikompilasi sepenuhnya, tetapi ketika dijalankan, pengecualian penunjuk nol akan dilemparkan. Di antara mereka, Integer100 adalah objek tipe integer, yang tentu saja dapat menunjuk ke nol. Tetapi di baris kedua, Integer100 akan unboxed, yaitu, metode intvalue () akan dieksekusi pada objek nol, dan tentu saja, pengecualian penunjuk nol akan dilemparkan. Oleh karena itu, saat unboxing, Anda harus memperhatikan apakah objek kelas yang dienkapsulasi adalah nol.
Perangkap 2
Integer I1 = 100;
Integer I2 = 100;
Integer I3 = 300;
Integer I4 = 300;
System.out.println (i1 == i2);
System.out.println (i3 == i4);
Karena I1, I2, I3, dan I4 semuanya adalah tipe integer, kami berpikir bahwa hasil berjalan harus salah. Namun, hasil berjalan yang sebenarnya adalah "System.out.println (I1 == I2);" Yang benar, tetapi "System.out.println (i3 == i4);" yang salah. Ini berarti bahwa referensi dari dua jenis integer, I1 dan I2, menunjuk ke objek yang sama, sementara I3 dan I4, menunjuk ke berbagai objek. Mengapa? Bukankah mereka semua disebut metode integer.valueof (int i)?
Mari kita lihat metode integer.valueof (int i) lagi.
/** * Mengembalikan contoh <tt> integer </tt> yang mewakili nilai * <tt> int </tt> yang ditentukan. * Jika instance <tt> integer </tt> baru tidak diperlukan, metode ini * umumnya harus digunakan dalam preferensi untuk konstruktor * {@link #integer (int)}, karena metode ini cenderung menghasilkan * ruang ruang dan waktu yang jauh lebih baik dengan caching * Nilai yang sering diminta. * * @param I nilai <code> int </code>. * @return a <tt> integer </tt> instance mewakili <tt> i </tt>. * @since 1.5 */ Nilai integer statis publik (int i) {if (i> = -128 && i <= integercache.high) return integercache.cache [i + 128]; lain mengembalikan bilangan bulat baru (i); }Kita dapat melihat bahwa ketika i> =-128 dan i <= integercache.high, integercache.cache [i + 128] dikembalikan secara langsung. Di antara mereka, Integercache adalah kelas integer statis internal, dan kode aslinya adalah sebagai berikut:
Private Static Class Integercache {static final int high; cache integer final statis []; static {final int low = -128; // Nilai tinggi dapat dikonfigurasi oleh properti int h = 127; if (integercacheHighPropValue! = null) {// Gunakan long.decode di sini untuk menghindari memohon metode yang // memerlukan cache otoboksing integer untuk diinisialisasi int i = long.decode (integercacheHighPropValue) .IntValue (); i = Math.max (i, 127); // Ukuran array maksimum adalah integer.max_value h = math.min (i, integer.max_value - -low); } tinggi = h; cache = bilangan bulat baru [(tinggi - rendah) + 1]; int j = rendah; untuk (int k = 0; k <cache.length; k ++) cache [k] = bilangan bulat baru (j ++); } private integercache () {}}Kita dapat dengan jelas melihat bahwa integercache memiliki cache variabel anggota statis, yang merupakan array dengan 256 elemen. Cache juga diinisialisasi dalam integercache, yaitu elemen i-th adalah objek integer dengan nilai I-128. -128 hingga 127 adalah objek integer yang paling umum digunakan, dan pendekatan ini juga sangat meningkatkan kinerja. Juga karena ini "integeri1 = 100; integer i2 = 100;", i1 dan i2 mendapatkan objek yang sama.
Membandingkan percobaan kedua dalam ekstensi, kami belajar bahwa ketika kelas enkapsulasi berjalan == dengan tipe dasar, kelas enkapsulasi akan unbox, dan hasil unboxing dibandingkan dengan tipe dasar; Sementara ketika dua kelas enkapsulasi berjalan == dengan objek lain, mereka membandingkan alamat dua objek, yaitu, untuk menentukan apakah dua referensi menunjuk ke objek yang sama.
Artikel di atas secara singkat membahas pengemasan dan unboxing otomatis Java dan perangkapnya adalah semua konten yang saya bagikan dengan Anda. Saya harap ini dapat memberi Anda referensi dan saya harap Anda dapat mendukung wulin.com lebih lanjut.