JavaRush /Java 博客 /Random-ZH /Java字节码简介
billybonce
第 29 级
Москва

Java字节码简介

已在 Random-ZH 群组中发布
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