JVM Internal, Bagian 2 - Struktur File Kelas

Halo semuanya! Terjemahan artikel disiapkan khusus untuk siswa kursus Java Developer .




Kami terus berbicara tentang bagaimana Java Virtual Machine bekerja secara internal. Dalam artikel sebelumnya ( asli dalam bahasa Inggris ), kami memeriksa subsistem pemuatan kelas. Pada artikel ini kita akan berbicara tentang struktur file kelas.

Seperti yang telah kita ketahui, semua kode sumber yang ditulis dalam bahasa pemrograman Java pertama kali dikompilasi menjadi bytecode menggunakan kompiler javac , yang merupakan bagian dari Java Development Kit. Bytecode disimpan dalam file biner dalam file kelas khusus. Kemudian file-file kelas ini secara dinamis (jika perlu) dimuat ke dalam memori oleh pemuat kelas (ClassLoader).


Gambar - Kompilasi kode sumber Java

Setiap file dengan .java dikompilasi menjadi setidaknya satu file .class . Untuk setiap kelas, antarmuka, dan modul yang ditentukan dalam kode sumber, satu file .class dibuat. Ini juga berlaku untuk antarmuka dan kelas bersarang.

Catatan - untuk kesederhanaan, file dengan ekstensi .class akan disebut "file kelas".

Mari kita menulis program sederhana.

 public class ClassOne{ public static void main(String[] args){ System.out.println("Hello world"); } static class StaticNestedClass{ } } class ClassTwo{ } interface InterfaceOne{ } 

Menjalankan javac untuk file ini akan menghasilkan file-file berikut.

 ClassOne$StaticNestedClass.class ClassOne.class ClassTwo.class InterfaceOne.class 

Seperti yang Anda lihat, file kelas terpisah dibuat untuk setiap kelas dan antarmuka.

Apa yang ada di dalam file kelas?


File kelas dalam format biner. Informasi di dalamnya biasanya ditulis tanpa lekukan antara potongan informasi yang berurutan, semuanya selaras dengan batas byte. Semua nilai 16-bit dan 32-bit ditulis menggunakan dua atau empat byte 8-bit berturut-turut.

File kelas berisi informasi berikut.

Nomor ajaib, tanda tangan . Empat byte pertama dari setiap file kelas selalu 0xCAFEBABE . Keempat byte ini mengidentifikasi file kelas Java.

Versi file. Empat byte berikutnya berisi versi utama dan kecil file. Bersama-sama, angka-angka ini menentukan versi format file kelas. Jika file kelas memiliki versi utama utama M dan minor, maka kami menetapkan versi ini sebagai Mm

Setiap JVM memiliki batasan pada versi file kelas yang didukung. Misalnya, Java 11 mendukung versi utama dari 45 hingga 55, Java 12 - dari 45 hingga 56.

Kelompok konstanta. Tabel struktur yang mewakili konstanta string, nama kelas, antarmuka, bidang, metode, dan konstanta lain yang ada di struktur ClassFile dan substrukturnya. Setiap elemen pool konstan dimulai dengan tag byte tunggal yang mendefinisikan tipe konstanta. Bergantung pada jenis konstanta, byte berikut ini dapat berupa nilai konstan langsung atau referensi ke elemen lain dalam kumpulan.

Akses bendera. Daftar bendera yang menunjukkan kelas adalah antarmuka, publik atau pribadi, kelas akhir atau tidak. Berbagai flag seperti ACC_PUBLIC , ACC_FINAL , ACC_INTERFACE , ACC_ENUM , dll. Dijelaskan dalam Spesifikasi Mesin Virtual Java.

Kelas ini. Tautkan ke entri di kumpulan konstan.

Kelas super. Tautkan ke entri di kumpulan konstan.

Antarmuka Jumlah antarmuka yang diterapkan oleh kelas.

Jumlah kolom. Jumlah bidang dalam kelas atau antarmuka.

Bidang Setelah jumlah bidang, tabel struktur dengan panjang variabel mengikuti. Satu untuk setiap bidang dengan deskripsi jenis dan nama bidang (dengan mengacu pada kumpulan konstanta).

Jumlah metode. Jumlah metode di kelas atau antarmuka. Jumlah ini hanya mencakup metode yang secara eksplisit didefinisikan di kelas, tanpa metode yang diwarisi dari kacamata super.

Metode Selanjutnya adalah metode itu sendiri. Untuk setiap metode, terdapat informasi berikut: deskriptor metode (jenis dan daftar argumen kembali), jumlah kata yang diperlukan untuk variabel lokal metode, jumlah maksimum kata tumpukan yang diperlukan untuk metode operan tumpukan, tabel pengecualian yang ditangkap oleh metode, metode bytecode, dan tabel nomor baris.

Jumlah atribut. Jumlah atribut dalam kelas, antarmuka, atau modul ini.

Atribut Jumlah atribut diikuti oleh tabel atau struktur panjang variabel yang menggambarkan setiap atribut. Sebagai contoh, selalu ada atribut "SourceFile". Ini berisi nama file sumber dari mana file kelas dikompilasi.

Meskipun file kelas tidak langsung dapat dibaca manusia, ada alat di JDK yang disebut javap yang menampilkan kontennya dalam format yang mudah.

Mari kita menulis program Java sederhana seperti yang ditunjukkan di bawah ini.

 package bytecode; import java.io.Serializable; public class HelloWorld implements Serializable, Cloneable { public static void main(String[] args) { System.out.println("Hello World"); } } 

Mari mengkompilasi program ini dengan javac , yang akan membuat file HelloWorld.class , dan menggunakan javap untuk melihat file HelloWorld.class . Menjalankan javap dengan opsi -v (verbose) untuk HelloWorld.class memberikan hasil sebagai berikut:

 Classfile /Users/apersiankite/Documents/code_practice/java_practice/target/classes/bytecode/HelloWorld.class Last modified 02-Jul-2019; size 606 bytes MD5 checksum 6442d93b955c2e249619a1bade6d5b98 Compiled from "HelloWorld.java" public class bytecode.HelloWorld implements java.io.Serializable,java.lang.Cloneable minor version: 0 major version: 55 flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #5 // bytecode/HelloWorld super_class: #6 // java/lang/Object interfaces: 2, fields: 0, methods: 2, attributes: 1 Constant pool: #1 = Methodref #6.#22 // java/lang/Object."<init>":()V #2 = Fieldref #23.#24 // java/lang/System.out:Ljava/io/PrintStream; #3 = String #25 // Hello World #4 = Methodref #26.#27 // java/io/PrintStream.println:(Ljava/lang/String;)V #5 = Class #28 // bytecode/HelloWorld #6 = Class #29 // java/lang/Object #7 = Class #30 // java/io/Serializable #8 = Class #31 // java/lang/Cloneable #9 = Utf8 <init> #10 = Utf8 ()V #11 = Utf8 Code #12 = Utf8 LineNumberTable #13 = Utf8 LocalVariableTable #14 = Utf8 this #15 = Utf8 Lbytecode/HelloWorld; #16 = Utf8 main #17 = Utf8 ([Ljava/lang/String;)V #18 = Utf8 args #19 = Utf8 [Ljava/lang/String; #20 = Utf8 SourceFile #21 = Utf8 HelloWorld.java #22 = NameAndType #9:#10 // "<init>":()V #23 = Class #32 // java/lang/System #24 = NameAndType #33:#34 // out:Ljava/io/PrintStream; #25 = Utf8 Hello World #26 = Class #35 // java/io/PrintStream #27 = NameAndType #36:#37 // println:(Ljava/lang/String;)V #28 = Utf8 bytecode/HelloWorld #29 = Utf8 java/lang/Object #30 = Utf8 java/io/Serializable #31 = Utf8 java/lang/Cloneable #32 = Utf8 java/lang/System #33 = Utf8 out #34 = Utf8 Ljava/io/PrintStream; #35 = Utf8 java/io/PrintStream #36 = Utf8 println #37 = Utf8 (Ljava/lang/String;)V { public bytecode.HelloWorld(); descriptor: ()V flags: (0x0001) ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 4: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lbytecode/HelloWorld; public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=1, args_size=1 0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3 // String Hello World 5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return LineNumberTable: line 7: 0 line 8: 8 LocalVariableTable: Start Length Slot Name Signature 0 9 0 args [Ljava/lang/String; } SourceFile: "HelloWorld.java" 

Di sini Anda dapat melihat bahwa kelasnya bersifat publik dan memiliki 37 entri di kumpulan konstan. Ada satu atribut (SourceFile di bawah), kelas mengimplementasikan dua antarmuka (Serializable, Cloneable), tidak memiliki bidang dan ada dua metode.

Anda mungkin telah memperhatikan bahwa hanya ada satu metode utama statis dalam kode sumber, tetapi file kelas mengatakan bahwa ada dua metode. Ingat konstruktor default - ini adalah konstruktor tanpa argumen yang ditambahkan oleh kompiler javac , yang bytecodenya juga terlihat di output. Konstruktor dianggap sebagai metode.

Anda dapat membaca lebih lanjut tentang javap di sini .

Kiat : Anda juga dapat menggunakan javap untuk melihat perbedaan lambda dari kelas dalam anonim.

Source: https://habr.com/ru/post/id478584/


All Articles