JavaRush /Blog Java /Random-VI /Giới thiệu về mã byte Java
billybonce
Mức độ
Москва

Giới thiệu về mã byte Java

Xuất bản trong nhóm
IntellijIDEA có một tính năng tuyệt vời - hiển thị mã byte, cho phép bạn xem cách thức và cuối cùng JRE sẽ thực thi mã đã viết.(Tuy nhiên, đây cũng là một số giải thích về mã byte máy của trình biên dịch để dễ đọc) Tìm thấy trong View-> Hiển thị mã Byte Chức năng của nó - phân tích các tệp .class - đã biên dịch. Bạn có thể tìm thấy mô tả về các lệnh tại liên kết Wikipedia .

Theo đó, nảy sinh ý tưởng phân tích mã byte cho hai phiên bản của phương thức chính với việc khởi tạo các dòng giống hệt nhau và cố gắng làm rõ lý do tại sao chúng cho kết quả khác nhau: Tùy chọn 1: (nếu chúng ta so sánh str1==str2, chúng ta sẽ nhận được sai) Tùy chọn 2 : (nếu so sánh str3== public static void main(String[] args){ String str1 = new String("test"); String str2 = new String("test"); } str4 thì ta đúng) public static void main(String[] args){ String str3 = "test"; String str4 = "test"; } Bytecode của tùy chọn đầu tiên (trong ngoặc vuông [] sẽ có trạng thái của ngăn xếp sau khi lệnh được thực thi (trên cùng của ngăn xếp bên phải)): Bytecode của tùy chọn thứ hai: Liên kết để đọc thêm: 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 Vậy tại sao các chuỗi bằng nhau trong một trường hợp mà không phải trong trường hợp kia? Bởi vì trong trường hợp Chuỗi mới, nhóm hằng số chuỗi bị bỏ qua và một bản sao mới của chuỗi được tạo (liên kết src6 về điều này). Và mặc dù mã byte không thực sự giúp làm rõ điều này, nhưng rõ ràng là trong trường hợp thứ hai, nó thực hiện ít thao tác hơn và do đó tùy chọn này tốt hơn. 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 //количество локальных переменных метода



Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION