JavaRush /Blog Java /Random-ES /Introducción a los códigos de bytes de Java
billybonce
Nivel 29
Москва

Introducción a los códigos de bytes de Java

Publicado en el grupo Random-ES
IntellijIDEA tiene una característica maravillosa: mostrar código de bytes, que le permite ver cómo y finalmente el JRE ejecutará el código escrito (sin embargo, esto también es una interpretación del código de bytes de la máquina por parte del compilador para facilitar la lectura). Se encuentra en Ver-> Mostrar código de bytes Qué hace: analiza archivos .class compilados. Las descripciones de los comandos se pueden encontrar en el enlace de Wikipedia .

En consecuencia, surgió la idea de analizar los códigos de bytes para dos versiones del método principal con inicialización de líneas idénticas, y tratar de aclarar por qué dan resultados diferentes: Opción 1: (si comparamos str1==str2, obtenemos false) Opción 2 : (si comparamos str3== public static void main(String[] args){ String str1 = new String("test"); String str2 = new String("test"); } str4, entonces obtenemos verdadero) public static void main(String[] args){ String str3 = "test"; String str4 = "test"; } Código de bytes de la primera opción (entre corchetes [] estará el estado de la pila después de ejecutar el comando (parte superior de la pila a la derecha)): Código de bytes de la segunda opción: Enlaces para leer más: 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 Entonces, ¿por qué las cadenas son iguales en un caso y no en el otro? Porque en el caso de una cadena nueva, el grupo de constantes de cadena se ignora y se crea una nueva copia de la cadena (enlace src6 sobre esto). Y aunque el bytecode no ayudó mucho a aclarar esto, es obvio que en el segundo caso realiza menos operaciones, por lo que esta opción es mejor. 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 с аргументами с вершины стека - //после вызова инициализирующего метода для стринг(и его внутренних манипуляций со стеком, //которые аналогично можно посмотреть в bytecódigoе java.lang.String ) //- в стеке будет enlace на проинициализированную строку: [value_result_string] //Почему для инициализации String(String) нужно три аргумента в стеке: //1)enlace на входной аргумент 2)новая строка, 3)хешcódigo строки 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 - инициализаций //(и если её не хватит - то всё вылетит с Cómoим-нибудь 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 (который компилятор дописывает за нас Cómo успешный конец метода) L3 LOCALVARIABLE args [Ljava/lang/String; L0 L3 0 //список локальных переменных, под которые выделяется память LOCALVARIABLE str1 Ljava/lang/String; L1 L3 1 //например: L1(метка где записан código) L3(метка где описан тип un objetoа и выделяется память) 1(локальный номер un objetoа) LOCALVARIABLE str2 Ljava/lang/String; L2 L3 2 // MAXSTACK = 1 //максимальная глубина стека для метода MAXLOCALS = 3 //количество локальных переменных метода



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