JavaRush /Java Blog /Random EN /Introduction to Java bytecodes
billybonce
Level 29
Москва

Introduction to Java bytecodes

Published in the Random EN group
IntellijIDEA has a wonderful feature - show bytecode, which allows you to see how and ultimately the JRE will execute the written code. (However, this is also some interpretation of the machine bytecode by the compiler for ease of reading) Found in View->Show Byte Code What it does - analyzes compiled .class - files. Descriptions of the commands can be found at the Wikipedia link .

Accordingly, the idea arose to parse the bytecodes for two versions of the main method with initialization of identical lines, and try to clarify why they give different results: Option 1: (if we compare str1==str2, we get false) Option 2: (if we compare str3== public static void main(String[] args){ String str1 = new String("test"); String str2 = new String("test"); } str4 , then we get true) public static void main(String[] args){ String str3 = "test"; String str4 = "test"; } Bytecode of the first option (in square brackets [] there will be the state of the stack after the command is executed (top of the stack on the right)): Bytecode of the second option: Links to read more: 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 So why are the strings equal in one case and not in the other? Because in the case of new String, the string constant pool is ignored, and a new copy of the string is created (link src6 about this). And although the bytecode did not really help clarify this, it is obvious that in the second case it performs fewer operations, and therefore this option is better. 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 //количество локальных переменных метода



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