JavaRush /Java Blog /Random-TW /Java字節碼簡介
billybonce
等級 29
Москва

Java字節碼簡介

在 Random-TW 群組發布
IntellijIDEA有一個很棒的功能——顯示字節碼,它可以讓你看到JRE如何以及最終將執行編寫的程式碼。(不過,這也是編譯器為了方便閱讀而對機器字節碼的一些解釋)可以在View->中找到顯示位元組程式碼 它的作用 - 分析編譯的 .class 檔案。這些命令的描述可以在維基百科連結中找到。

因此,出現了透過初始化相同行來解析main 方法的兩個版本的字節碼的想法,並嘗試澄清為什麼它們給出不同的結果: 選項1:(如果我們比較str1==str2,我們得到false)選項 2 :(如果我們比較 str3== public static void main(String[] args){ String str1 = new String("test"); String str2 = new String("test"); } str4 ,那麼我們得到 true) public static void main(String[] args){ String str3 = "test"; String str4 = "test"; } 第一個選項的字節碼(方括號 [] 中將是命令執行後堆疊的狀態(右側堆疊頂部)): 第二個選項的字節碼: 閱讀更多內容的連結: 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 那麼為什麼字串在一種情況下相等而在另一種情況下不相等?因為在 new String 的情況下,字串常數池被忽略,並建立字串的新副本(有關此的連結 src6)。儘管字節碼並沒有真正幫助澄清這一點,但顯然在第二種情況下它執行的操作更少,因此這個選項更好。 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 //количество локальных переменных метода



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