Objek dan array

Selamat datang di edisi lain Under The Hood . Kolom ini berfokus pada teknologi yang mendasari Java. Ini bertujuan untuk memberikan gambaran sekilas kepada para pengembang tentang mekanisme yang membuat program Java mereka berjalan. Artikel bulan ini membahas bytecode yang menangani objek dan array.

Mesin berorientasi objek

Mesin virtual Java (JVM) bekerja dengan data dalam tiga bentuk: objek, referensi objek, dan tipe primitif. Objek berada di heap yang dikumpulkan sampah. Referensi objek dan tipe primitif berada di tumpukan Java sebagai variabel lokal, di heap sebagai variabel instan objek, atau di area metode sebagai variabel kelas.

Di mesin virtual Java, memori dialokasikan di heap yang dikumpulkan sampah hanya sebagai objek. Tidak ada cara untuk mengalokasikan memori untuk tipe primitif di heap, kecuali sebagai bagian dari sebuah objek. Jika Anda ingin menggunakan tipe primitif yang membutuhkan Objectreferensi, Anda dapat mengalokasikan objek pembungkus untuk tipe dari java.langpaket. Misalnya, ada Integerkelas yang membungkus inttipe dengan objek. Hanya referensi objek dan tipe primitif yang dapat berada di tumpukan Java sebagai variabel lokal. Objek tidak pernah bisa berada di tumpukan Java.

Pemisahan arsitektural objek dan tipe primitif di JVM tercermin dalam bahasa pemrograman Java, di mana objek tidak dapat dideklarasikan sebagai variabel lokal. Hanya referensi objek yang dapat dideklarasikan seperti itu. Setelah deklarasi, referensi objek tidak merujuk ke apa pun. Hanya setelah referensi diinisialisasi secara eksplisit - baik dengan referensi ke objek yang ada atau dengan panggilan ke new- apakah referensi merujuk ke objek sebenarnya.

Dalam set instruksi JVM, semua objek dibuat instance-nya dan diakses dengan set opcode yang sama, kecuali untuk array. Di Java, array adalah objek yang lengkap, dan, seperti objek lain di program Java, dibuat secara dinamis. Referensi array dapat digunakan di mana pun referensi ke tipe Objectdipanggil, dan metode apa pun Objectdapat dipanggil pada array. Namun, di mesin virtual Java, array ditangani dengan bytecode khusus.

Seperti objek lainnya, array tidak bisa dideklarasikan sebagai variabel lokal; hanya referensi array yang bisa. Objek array itu sendiri selalu berisi array tipe primitif atau array referensi objek. Jika Anda mendeklarasikan larik objek, Anda mendapatkan larik referensi objek. Objek itu sendiri harus secara eksplisit dibuat newdan ditetapkan ke elemen array.

Opcode untuk objek

Instansiasi objek baru dilakukan melalui

new

opcode. Dua operan satu byte mengikuti

new

opcode. Kedua byte ini digabungkan untuk membentuk indeks 16-bit ke dalam kumpulan konstan. Elemen kumpulan konstan pada offset yang ditentukan memberikan informasi tentang kelas objek baru. JVM membuat instance baru dari objek di heap dan mendorong referensi ke objek baru ke tumpukan, seperti yang ditunjukkan di bawah ini.

Pembuatan objek
Opcode Operand (s) Deskripsi
new indexbyte1, indexbyte2 membuat objek baru di heap, mendorong referensi

Tabel berikutnya menunjukkan opcode yang meletakkan dan mendapatkan bidang objek. Opcode ini, putfield dan getfield, beroperasi hanya pada bidang yang merupakan variabel instan. Variabel statis diakses oleh putstatic dan getstatic, yang akan dijelaskan nanti. Instruksi putfield dan getfield masing-masing mengambil dua operan satu byte. Operan digabungkan untuk membentuk indeks 16-bit ke dalam kumpulan konstan. Item kumpulan konstan pada indeks tersebut berisi informasi tentang jenis, ukuran, dan offset bidang. Referensi objek diambil dari stack di instruksi putfield dan getfield. Instruksi putfield mengambil nilai variabel contoh dari tumpukan, dan instruksi getfield mendorong nilai variabel contoh yang diambil ke tumpukan.

Mengakses variabel contoh
Opcode Operand (s) Deskripsi
putfield indexbyte1, indexbyte2 set field, ditunjukkan oleh indeks, dari objek ke nilai (keduanya diambil dari tumpukan)
getfield indexbyte1, indexbyte2 mendorong bidang, ditunjukkan oleh indeks, dari objek (diambil dari tumpukan)

Variabel kelas diakses melalui opcode getstatic dan putstatic, seperti yang ditunjukkan pada tabel di bawah. Baik getstatic dan putstatic mengambil dua operand satu byte, yang digabungkan oleh JVM untuk membentuk offset 16-bit unsigned ke dalam kumpulan konstan. Item kumpulan konstan di lokasi itu memberikan informasi tentang satu bidang statis kelas. Karena tidak ada objek tertentu yang dikaitkan dengan bidang statis, tidak ada referensi objek yang digunakan oleh getstatic atau putstatic. Instruksi putstatic mengambil nilai untuk ditetapkan dari stack. Instruksi getstatic mendorong nilai yang diambil ke tumpukan.

Mengakses variabel kelas
Opcode Operand (s) Deskripsi
putstatic indexbyte1, indexbyte2 set field, ditunjukkan oleh indeks, dari objek ke nilai (keduanya diambil dari tumpukan)
getstatic indexbyte1, indexbyte2 mendorong bidang, ditunjukkan oleh indeks, dari objek (diambil dari tumpukan)

Opcode berikut memeriksa untuk melihat apakah referensi objek di bagian atas tumpukan merujuk ke instance kelas atau antarmuka yang diindeks oleh operan setelah opcode. Instruksi checkcast menampilkan CheckCastExceptionjika objek tersebut bukan instance dari kelas atau antarmuka yang ditentukan. Jika tidak, checkcast tidak melakukan apa-apa. Referensi objek tetap ada di tumpukan dan eksekusi dilanjutkan pada instruksi berikutnya. Instruksi ini memastikan bahwa gips aman pada waktu pengoperasian dan merupakan bagian dari selimut keamanan JVM.

Instanceof instruksi memunculkan referensi objek dari atas tumpukan dan mendorong benar atau salah. Jika objek memang merupakan turunan dari kelas atau antarmuka yang ditentukan, maka true didorong ke tumpukan, jika tidak, salah didorong ke tumpukan. Instruksi instanceof digunakan untuk mengimplementasikan instanceofkata kunci Java, yang memungkinkan pemrogram untuk menguji apakah suatu objek adalah turunan dari kelas atau antarmuka tertentu.

Ketik pemeriksaan
Opcode Operand (s) Deskripsi
checkcast indexbyte1, indexbyte2 Melempar ClassCastException jika objectref di tumpukan tidak dapat dilemparkan ke kelas pada indeks
instanceof indexbyte1, indexbyte2 Mendorong true jika objectref pada stack adalah turunan kelas pada indeks, jika tidak mendorong false

Opcode untuk array

Instansiasi larik baru dilakukan melalui opcode larik baru, larik baru, dan larik multi. Opcode newarray digunakan untuk membuat array tipe primitif selain referensi objek. Tipe primitif tertentu ditentukan oleh operand satu-byte setelah opcode array baru. Instruksi newarray dapat membuat array untuk byte, short, char, int, long, float, double, atau boolean.

Instruksi anewarray membuat larik referensi objek. Dua operan satu byte mengikuti opcode anewarray dan digabungkan untuk membentuk indeks 16-bit ke dalam kumpulan konstan. Deskripsi kelas objek yang akan dibuat array ditemukan di kumpulan konstan pada indeks yang ditentukan. Instruksi ini mengalokasikan ruang untuk larik referensi objek dan menginisialisasi referensi ke null.

The multianewarray instruction is used to allocate multidimensional arrays -- which are simply arrays of arrays -- and could be allocated with repeated use of the anewarray and newarray instructions. The multianewarray instruction simply compresses the bytecodes needed to create multidimensional arrays into one instruction. Two one-byte operands follow the multianewarray opcode and are combined to form a 16-bit index into the constant pool. A description of the class of object for which the array is to be created is found in the constant pool at the specified index. Immediately following the two one-byte operands that form the constant pool index is a one-byte operand that specifies the number of dimensions in this multidimensional array. The sizes for each dimension are popped off the stack. This instruction allocates space for all arrays that are needed to implement the multidimensional arrays.

Creating new arrays
Opcode Operand(s) Description
newarray atype pops length, allocates new array of primitive types of type indicated by atype, pushes objectref of new array
anewarray indexbyte1, indexbyte2 pops length, allocates a new array of objects of class indicated by indexbyte1 and indexbyte2, pushes objectref of new array
multianewarray indexbyte1, indexbyte2, dimensions pops dimensions number of array lengths, allocates a new multidimensional array of class indicated by indexbyte1 and indexbyte2, pushes objectref of new array

The next table shows the instruction that pops an array reference off the top of the stack and pushes the length of that array.

Getting the array length
Opcode Operand(s) Description
arraylength (none) pops objectref of an array, pushes length of that array

The following opcodes retrieve an element from an array. The array index and array reference are popped from the stack, and the value at the specified index of the specified array is pushed back onto the stack.

Retrieving an array element
Opcode Operand(s) Description
baload (none) pops index and arrayref of an array of bytes, pushes arrayref[index]
caload (none) pops index and arrayref of an array of chars, pushes arrayref[index]
saload (none) pops index and arrayref of an array of shorts, pushes arrayref[index]
iaload (none) pops index and arrayref of an array of ints, pushes arrayref[index]
laload (none) pops index and arrayref of an array of longs, pushes arrayref[index]
faload (none) pops index and arrayref of an array of floats, pushes arrayref[index]
daload (none) pops index and arrayref of an array of doubles, pushes arrayref[index]
aaload (none) pops index and arrayref of an array of objectrefs, pushes arrayref[index]

The next table shows the opcodes that store a value into an array element. The value, index, and array reference are popped from the top of the stack.

Storing to an array element
Opcode Operand(s) Description
bastore (none) pops value, index, and arrayref of an array of bytes, assigns arrayref[index] = value
castore (none) pops value, index, and arrayref of an array of chars, assigns arrayref[index] = value
sastore (none) pops value, index, and arrayref of an array of shorts, assigns arrayref[index] = value
iastore (none) pops value, index, and arrayref of an array of ints, assigns arrayref[index] = value
lastore (none) pops value, index, and arrayref of an array of longs, assigns arrayref[index] = value
fastore (none) pops value, index, and arrayref of an array of floats, assigns arrayref[index] = value
dastore (none) pops value, index, and arrayref of an array of doubles, assigns arrayref[index] = value
aastore (none) pops nilai, indeks, dan arrayref dari sebuah array objekrefs, menetapkan arrayref [indeks] = nilai

Array tiga dimensi: simulasi mesin virtual Java

Applet di bawah ini mendemonstrasikan mesin virtual Java yang menjalankan urutan bytecode. Urutan bytecode dalam simulasi dihasilkan oleh javacuntuk initAnArray()metode kelas yang ditunjukkan di bawah ini:

kelas ArrayDemo {static void initAnArray () {int [] [] [] threeD = new int [5] [4] [3]; untuk (int i = 0; i <5; ++ i) {for (int j = 0; j <4; ++ j) {for (int k = 0; k <3; ++ k) {threeD [ i] [j] [k] = i + j + k; }}}}}

Kode bytecode yang dihasilkan oleh javacuntuk initAnArray()ditampilkan di bawah ini: