JavaRush /Java Blog /Random-ID /Pengantar bytecode Java
billybonce
Level 29
Москва

Pengantar bytecode Java

Dipublikasikan di grup Random-ID
IntellijIDEA memiliki fitur luar biasa - tampilkan bytecode, yang memungkinkan Anda melihat bagaimana dan pada akhirnya JRE akan mengeksekusi kode tertulis (Namun, ini juga merupakan beberapa interpretasi bytecode mesin oleh kompiler untuk kemudahan membaca) Ditemukan di View-> Tampilkan Kode Byte Apa fungsinya - menganalisis file .class - yang dikompilasi. Deskripsi perintah dapat ditemukan di tautan Wikipedia .

Oleh karena itu, muncul ide untuk mengurai bytecode untuk dua versi metode utama dengan inisialisasi baris yang identik, dan mencoba menjelaskan mengapa keduanya memberikan hasil yang berbeda: Opsi 1: (jika kita membandingkan str1==str2, kita mendapatkan false) Opsi 2 : (jika kita membandingkan str3== public static void main(String[] args){ String str1 = new String("test"); String str2 = new String("test"); } str4 , maka kita mendapatkan true) public static void main(String[] args){ String str3 = "test"; String str4 = "test"; } Bytecode dari opsi pertama (dalam tanda kurung siku [] akan ada status tumpukan setelah perintah dijalankan (bagian atas tumpukan di sebelah kanan)): Bytecode opsi kedua: Tautan untuk membaca lebih lanjut: src1: http://cs.au.dk/~mis /dOvs/jvmspec/ref--33.html src2: http://mihaimoldovan.com/download/Inside- Java-Virtual-Machine.pdf src3: http://en.wikipedia.org/wiki/Java_class_file#The_constant_pool src4 : http://en.wikipedia.org/wiki/Java_bytecode_instruction_listings src5: http://stackoverflow.com/questions /10209952/java-constant-pool src6: http://stackoverflow.com/questions/14150628/string-constant -pool-java Jadi mengapa stringnya sama di satu kasus dan tidak di kasus lain? Karena dalam kasus String baru, kumpulan konstanta string diabaikan, dan salinan string baru dibuat (tautan src6 tentang ini). Dan meskipun bytecode tidak terlalu membantu memperjelas hal ini, jelas bahwa dalam kasus kedua ia melakukan lebih sedikit operasi, dan oleh karena itu opsi ini lebih baik. public static main([Ljava/lang/String;)V L0 LINENUMBER 5 L0 NEW java/lang/String //новая строка - кладем ссылку на класс "String "на вершину стека: [value_string] DUP //копируем ссылку на вершине стека: [value_string, value_string] LDC "test" //кладём в стек ссылку на "test" из constant pool(а если в нём еще нет ссылки на "test", //то она также остается в constant pool'e): [value_string, value_string, value_test] INVOKESPECIAL java/lang/String. (Ljava/lang/String;)V //вызов new для String с аргументами с вершины стека - //после вызова инициализирующего метода для стринг(и его внутренних манипуляций со стеком, //которые аналогично можно посмотреть в bytecodeе java.lang.String ) //- в стеке будет link на проинициализированную строку: [value_result_string] //Почему для инициализации String(String) нужно три аргумента в стеке: //1)link на входной аргумент 2)новая строка, 3)хешcode строки ASTORE 1 //сохраняем ссылку с вершины стека в локальную переменную(1) с вершины стека: [ ] L1 LINENUMBER 6 L1 NEW java/lang/String //аналогично первой строке DUP LDC "test" INVOKESPECIAL java/lang/String. (Ljava/lang/String;)V ASTORE 2 L2 LINENUMBER 7 L2 RETURN //return void - компилятор дописывает за нас если метод возвращает void L3 LOCALVARIABLE args [Ljava/lang/String; L0 L3 0 // список локальных переменных метода LOCALVARIABLE str3 Ljava/lang/String; L1 L3 1 // L1(метка где операции с локальной переменной) L3(метка где описание что это за локальная переменная) 1(номер локальной переменной) LOCALVARIABLE str4 Ljava/lang/String; L2 L3 2 // MAXSTACK = 3 //максимальная глубина стека метода MAXLOCALS = 3 //количество локальных переменных метода // //То есть сначала JRE будет выделять память при //вызове метода учитывая всю вложенность вызовов методов и new - инициализаций //(и если её не хватит - то всё вылетит с Howим-нибудь OutOfMemory //эксепшном), а только потом будут производиться операции public static main([Ljava/lang/String;)V L0 LINENUMBER 5 L0 LDC "test" //берем ссылку на "test" из constant_pool и кладем на вершину стека: [value_test] ASTORE 1 //забираем ссылку с вершины стека в переменную(1) str1 : [ ] L1 LINENUMBER 6 L1 LDC "test" //берем ссылку на "test" из constant_pool и кладем на вершину стека: [value_test] ASTORE 2 //забираем ссылку с вершины стека в переменную(2) str2: [ ] L2 LINENUMBER 7 L2 RETURN //return void (который компилятор дописывает за нас How успешный конец метода) L3 LOCALVARIABLE args [Ljava/lang/String; L0 L3 0 //список локальных переменных, под которые выделяется память LOCALVARIABLE str1 Ljava/lang/String; L1 L3 1 //например: L1(метка где записан code) L3(метка где описан тип an object и выделяется память) 1(локальный номер an object) LOCALVARIABLE str2 Ljava/lang/String; L2 L3 2 // MAXSTACK = 1 //максимальная глубина стека для метода MAXLOCALS = 3 //количество локальных переменных метода



Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION