เพื่อนที่ศึกษา Java ควรรู้ไว้ว่า Java ใช้แบนเนอร์แห่งความเป็นอิสระของแพลตฟอร์มมาตั้งแต่เริ่มต้น โดยพูดว่า "เขียนครั้งเดียวทำงานได้ทุกที่" ที่จริงแล้ว เมื่อพูดถึงความไม่เกี่ยวข้อง แพลตฟอร์ม Java ก็มีความไม่เกี่ยวข้องอีกอย่างหนึ่ง ซึ่งก็คือความเป็นอิสระทางภาษา . เพื่อให้บรรลุความเป็นอิสระของภาษาแล้วโครงสร้างไฟล์ของชั้นเรียนในระบบ Java หรือ สิ่งสำคัญมากที่ต้องบอกว่าเป็น bytecode ที่จริงแล้ว Java มีข้อกำหนดสองชุดตั้งแต่เริ่มต้น ชุดหนึ่งคือข้อกำหนดภาษา Java และอีกชุดคือข้อกำหนดเฉพาะของ Java virtual machine ที่เกี่ยวข้องกับภาษาและกฎของ Java และข้อกำหนดเฉพาะของเครื่องเสมือนได้รับการออกแบบอย่างแท้จริงจากมุมมองข้ามแพลตฟอร์ม วันนี้เราจะยกตัวอย่างเชิงปฏิบัติเพื่อดูว่าไบต์โค้ดที่สอดคล้องกับไฟล์ Class ใน Java ควรมีลักษณะอย่างไร บทความนี้จะอธิบายโดยทั่วไปว่าเนื้อหาประกอบด้วยคลาสใดบ้าง จากนั้นจึงใช้คลาส Java จริงเพื่อวิเคราะห์โครงสร้างไฟล์ของคลาส
ก่อนดำเนินการต่อ เราต้องชี้แจงประเด็นต่อไปนี้ก่อน:
1) ไฟล์คลาสประกอบด้วยไบต์แบบ 8 ไบต์ สตรีมไบต์เหล่านี้ถูกจัดเรียงอย่างเคร่งครัดตามลำดับที่ระบุ และไม่มีช่องว่างระหว่างไบต์ สำหรับไฟล์ที่เกิน 8 ไบต์ ข้อมูลจะถูกจัดเก็บไว้ในลำดับ Big-Endian กล่าวคือไบต์ที่มีลำดับสูงจะถูกเก็บไว้ที่ที่อยู่ต่ำ และไบต์ที่มีลำดับต่ำจะถูกเก็บไว้ที่ที่อยู่สูง นี่เป็นกุญแจสำคัญสำหรับไฟล์คลาสข้ามแพลตฟอร์ม เนื่องจากสถาปัตยกรรม PowerPC ใช้ลำดับการจัดเก็บข้อมูล Big-Endian ในขณะที่โปรเซสเซอร์ซีรีส์ x86 ใช้ลำดับการจัดเก็บข้อมูล Little-Endian ดังนั้นเพื่อให้ไฟล์ Class ได้รับการดูแลภายใต้สถาปัตยกรรมโปรเซสเซอร์แต่ละตัว Unified storage ลำดับ ข้อมูลจำเพาะของเครื่องเสมือนจะต้องรวมเป็นหนึ่งเดียว
2) โครงสร้างไฟล์ Class ใช้โครงสร้างคล้ายภาษา C ในการจัดเก็บข้อมูล มีสองประเภทหลักของรายการข้อมูล หมายเลขที่ไม่ได้ลงนาม และตาราง ใช้เพื่อแสดงตัวเลข การอ้างอิงดัชนี และสตริง เช่น u1, u2 , u4 และ u8 แทนตัวเลขที่ไม่ได้ลงนามจำนวน 1 ไบต์, 2 ไบต์, 4 ไบต์ และ 8 ไบต์ ตามลำดับ และตารางนี้เป็นโครงสร้างแบบผสมที่ประกอบด้วยตัวเลขที่ไม่ได้ลงชื่อหลายจำนวนและตารางอื่นๆ บางทีทุกคนที่นี่อาจไม่ชัดเจนนักว่าตัวเลขและตารางที่ไม่ได้ลงชื่อคืออะไร แต่ก็ไม่สำคัญ ฉันจะอธิบายด้วยตัวอย่างเมื่อฉันยกตัวอย่างด้านล่าง
หลังจากชี้แจงสองประเด็นข้างต้นแล้ว เรามาดูข้อมูลเฉพาะที่มีอยู่ในสตรีมไบต์ที่จัดเรียงตามลำดับที่เข้มงวดในไฟล์ Class:
เมื่อดูภาพด้านบน มีสิ่งหนึ่งที่เราต้องใส่ใจ เช่น cp_info, cp_info แสดงถึงพูลคงที่ ในภาพด้านบน Constant_pool[constant_pool_count-1] ถูกใช้เพื่อแสดงค่าคงที่พูลด้วย Constant_pool_co unt-1 ค่าคงที่จะแสดงในรูปแบบของอาร์เรย์ที่นี่ แต่อย่าเข้าใจผิดว่าความยาวคงที่ของพูลคงที่ทั้งหมดเท่ากัน ที่จริงแล้ว สถานที่นี้ใช้วิธีการอาร์เรย์เพื่อความสะดวกในการอธิบายเท่านั้น ในภาษาการเขียนโปรแกรม อาร์เรย์ประเภท int จะมีความยาวเท่ากันในแต่ละ int หลังจากชี้แจงประเด็นนี้แล้ว ลองย้อนกลับไปดูว่าแต่ละรายการในภาพด้านบนหมายถึงอะไรโดยเฉพาะ
1) เลขมหัศจรรย์ u4 แทนเลขเวทย์มนตร์ และเลขเวทย์มนตร์มีขนาด 4 ไบต์ จริงๆ แล้วหมายความว่าไฟล์ประเภทนี้เป็นไฟล์ Class ไม่ใช่รูปภาพ JPG หรือภาพยนตร์ AVI หมายเลขวิเศษที่สอดคล้องกับไฟล์ Class คือ 0xCAFEBABE
2) u2 minor_version แสดงถึงหมายเลขเวอร์ชันรองของไฟล์ Class และหมายเลขเวอร์ชันนี้เป็นตัวเลขที่ไม่ได้ลงนามซึ่งเป็นตัวแทนประเภท u2
3) u2 major_version แสดงถึงหมายเลขเวอร์ชันหลักของไฟล์ Class และหมายเลขเวอร์ชันหลักคือตัวเลขที่ไม่ได้ลงชื่อซึ่งแสดงถึงประเภท u2 major_version และ minor_version ส่วนใหญ่จะใช้เพื่อระบุว่าเครื่องเสมือนปัจจุบันยอมรับเวอร์ชันปัจจุบันของไฟล์ Class หรือไม่ เวอร์ชันของไฟล์ Class ที่คอมไพล์โดยคอมไพเลอร์ Java เวอร์ชันต่างๆ จะแตกต่างกัน เครื่องเสมือนเวอร์ชันที่สูงกว่ารองรับโครงสร้างไฟล์คลาสที่คอมไพล์โดยคอมไพเลอร์เวอร์ชันต่ำกว่า ตัวอย่างเช่น เครื่องเสมือนที่สอดคล้องกับ Java SE 6.0 รองรับโครงสร้างไฟล์ Class ที่คอมไพล์โดยคอมไพเลอร์ Java SE 5.0 แต่ไม่ในทางกลับกัน
4) u2 Constant_pool_count แสดงถึงจำนวนพูลคงที่ ที่นี่เราต้องเน้นไปที่พูลคงที่ โปรดอย่าสับสนกับพูลคงที่รันไทม์ในโมเดลหน่วยความจำ Jvm พูลคงที่ในไฟล์ Class ส่วนใหญ่จะเก็บการอ้างอิงตัวอักษรและสัญลักษณ์ โดยที่ตัวอักษรส่วนใหญ่จะรวมสตริง ค่าคงที่สุดท้ายหรือ หรือค่าเริ่มต้นของคุณลักษณะบางอย่าง ฯลฯ ในขณะที่การอ้างอิงสัญลักษณ์ส่วนใหญ่จะเก็บชื่อแบบเต็มของคลาสและอินเทอร์เฟซ ชื่อฟิลด์และคำอธิบาย ชื่อวิธีการและคำอธิบายในที่นี้ แนวคิดของ descriptors เราจะพูดถึงในภายหลังเมื่อเราหารือเกี่ยวกับตารางฟิลด์และตารางวิธีการ นอกจากนี้ ทุกคนรู้ดีว่าโมเดลหน่วยความจำของ Jvm ประกอบด้วยฮีป สแต็ก พื้นที่เมธอด และตัวนับโปรแกรม และมีพื้นที่ในพื้นที่เมธอดที่เรียกว่าพูลคงที่รันไทม์ จริงๆ แล้วสิ่งที่จัดเก็บไว้ในพูลคงที่รันไทม์ ความเป็นอมตะของคอมไพเลอร์ การอ้างอิงตัวอักษรและสัญลักษณ์ต่าง ๆ แต่ค่าคงที่รันไทม์เป็นไดนามิก มันสามารถเพิ่มค่าคงที่อื่น ๆ ให้กับมันได้ที่รันไทม์
5) cp_info แสดงถึงพูลคงที่ ซึ่งมีการอ้างอิงตัวอักษรและสัญลักษณ์ต่างๆ ที่กล่าวถึงข้างต้น มีรายการข้อมูลทั้งหมด 14 รายการที่อยู่ในพูลคงที่ใน Java Virtual Machine Specification Java SE 7 Edition แต่ละค่าคงที่จะเป็นตาราง และค่าคงที่แต่ละรายการจะใช้แท็กบางส่วนทั่วไปเพื่อระบุประเภทค่าคงที่
รายละเอียดเฉพาะมีการอธิบายไว้โดยย่อด้านล่าง และเราจะปรับแต่งรายละเอียดเหล่านั้นในตัวอย่างภายหลัง
ค่าสถานะแท็ก CONSTANT_Utf8_info คือ 1, สตริงที่เข้ารหัส UTF-8 ค่าสถานะแท็ก CONSTANT_Integer_info คือ 3, ค่าสถานะแท็ก CONSTANT_Float_info ตามตัวอักษรจำนวนเต็มคือ 4, ค่าสถานะแท็กแท็ก CONSTANT_Long_info ตามตัวอักษรจำนวนเต็มแบบยาว บิตคือ 6, ค่าสถานะแท็ก CONSTANT_Class_info ตามตัวอักษรที่มีความแม่นยำสองเท่าคือ 7 แท็กการอ้างอิงเชิงสัญลักษณ์ CONSTANT_String_info ของคลาสหรืออินเทอร์เฟซคือ 8, แท็ก CONSTANT_Fieldref_info ตามตัวอักษรของประเภทสตริงคือ 9, การอ้างอิงเชิงสัญลักษณ์ของแท็กฟิลด์ CONSTANT_Methodref_info คือ 10, การอ้างอิงเชิงสัญลักษณ์ของวิธีการในคลาสแท็ก CONSTANT_InterfaceMethodref_info คือ 11, สัญลักษณ์ อ้างอิงถึงวิธีการในแท็กอินเทอร์เฟซ CONSTANT_NameAndType_info ตั้งค่าสถานะบิต 12 ชื่อของฟิลด์และวิธีการ และการอ้างอิงเชิงสัญลักษณ์ไปยังประเภทต่างๆ
6) u2 access_flags แสดงถึงข้อมูลการเข้าถึงของคลาสหรืออินเทอร์เฟซ ดังแสดงในรูปต่อไปนี้:
7) u2 this_class แสดงถึงดัชนีพูลคงที่ของคลาส โดยชี้ไปที่ค่าคงที่ของ CONSTANT_Class_info ในพูลคงที่
8) u2 super_class แสดงถึงดัชนีของคลาส super ซึ่งชี้ไปที่ค่าคงที่ของ CONSTANT_Class_info ในพูลคงที่
9) u2 interface_counts แสดงถึงจำนวนอินเทอร์เฟซ
10) อินเทอร์เฟซ u2[interface_counts] แสดงถึงตารางอินเทอร์เฟซ แต่ละรายการในนั้นชี้ไปที่ค่าคงที่ CONSTANT_Class_info ในพูลคงที่
11) u2 fields_count แสดงถึงจำนวนตัวแปรอินสแตนซ์และตัวแปรคลาสของคลาส
12) field_info fields[fields_count] แสดงถึงข้อมูลของตารางฟิลด์ โดยโครงสร้างของตารางฟิลด์จะแสดงด้านล่าง:
ในรูปด้านบน access_flags แสดงถึงการแสดงการเข้าถึงของฟิลด์ ตัวอย่างเช่น ฟิลด์เป็นแบบสาธารณะ ส่วนตัว และปกป้อง ฯลฯ name_index แสดงถึงชื่อฟิลด์ ซึ่งชี้ไปที่ค่าคงที่ประเภท CONSTANT_UTF8_info ในพูลค่าคงที่ descriptor_index แสดงถึง descriptor ของฟิลด์ ซึ่งชี้ไปที่ค่าคงที่ประเภท CONSTANT_UTF8_info ในพูลค่าคงที่ แอตทริบิวต์_count แสดงถึงจำนวนของตารางแอตทริบิวต์ ในตารางฟิลด์และตารางแอ็ตทริบิวต์ เป็นโครงสร้างที่ขยายได้ซึ่งใช้เพื่ออธิบายฟิลด์ วิธีการ และแอ็ตทริบิวต์คลาส เวอร์ชันต่างๆ ของเครื่องเสมือน Java รองรับจำนวนตารางแอ็ตทริบิวต์ที่แตกต่างกัน
13) u2 method_count แสดงถึงจำนวนตารางวิธีการ
14) method_info แสดงถึงโครงสร้างเฉพาะของตารางวิธีการดังแสดงในรูปด้านล่าง:
ในบรรดานั้น access_flags แสดงถึงการแสดงการเข้าถึงของเมธอด name_index แสดงถึงดัชนีของชื่อ descriptor_index แสดงถึง descriptor ของเมธอดattributes_count และ คุณลักษณะ_info มีความคล้ายคลึงกับตารางแอตทริบิวต์ในตารางฟิลด์ ยกเว้นว่าแอตทริบิวต์ในตารางแอตทริบิวต์ ในตารางฟิลด์และตารางเมธอดจะแตกต่างกัน เช่น แอ็ตทริบิวต์ Code ในตารางเมธอดแสดงถึงโค้ดของเมธอด แต่ไม่มีแอ็ตทริบิวต์ Code ในตารางฟิลด์ มีแอตทริบิวต์จำนวนเท่าใดในคลาสเฉพาะ เราจะกล่าวถึงในภายหลังเมื่อเราดูตารางคุณลักษณะในโครงสร้างไฟล์คลาส
15)attribute_count แสดงถึงจำนวนตารางแอตทริบิวต์ เมื่อพูดถึงตารางแอตทริบิวต์ เราต้องชี้แจงประเด็นต่อไปนี้:
ตารางแอตทริบิวต์มีอยู่ที่ส่วนท้ายของโครงสร้างไฟล์ Class ในตารางฟิลด์ ตารางเมธอด และแอตทริบิวต์รหัส กล่าวคือ ตารางคุณลักษณะอาจมีอยู่ในตารางแอตทริบิวต์ ความยาวของตารางคุณลักษณะไม่ได้รับการแก้ไข คุณลักษณะที่ต่างกันจะมีความยาวต่างกัน
หลังจากที่อธิบายองค์ประกอบของแต่ละรายการในโครงสร้างไฟล์ Class ข้างต้นแล้ว เราจะใช้ตัวอย่างที่เป็นประโยชน์เพื่ออธิบายเนื้อหาต่อไปนี้
คัดลอกรหัสรหัส ดังต่อไปนี้:
แพ็คเกจ com.ejushang.TestClass;
TestClass คลาสสาธารณะใช้ Super{
ส่วนตัวคงที่สุดท้าย int staticVar = 0;
int instanceVar ส่วนตัว = 0;
สาธารณะ int instanceMethod (พารามิเตอร์ int) {
ส่งคืนพารามิเตอร์+1;
-
-
อินเทอร์เฟซซุปเปอร์{ }
โครงสร้างไบนารีของ TestClass.class ที่สอดคล้องกับ TestClass.java ที่คอมไพล์ผ่าน javac ของ jdk1.6.0_37 แสดงในรูปด้านล่าง:
ต่อไป เราจะแยกวิเคราะห์ไบต์ในรูปด้านบนตามโครงสร้างไฟล์ของคลาสที่กล่าวถึงก่อนหน้านี้
1) Magic number <br/>จากโครงสร้างไฟล์ของ Class เรารู้ว่า 4 ไบต์แรกเป็นตัวเลขมหัศจรรย์ ในภาพด้านบน เนื้อหาจากที่อยู่ 00000000h-00000003h คือตัวเลขมหัศจรรย์ เราสามารถรู้เลขมหัศจรรย์ของไฟล์ Class ได้ คือ 0xCAFEBABE
2) หมายเลขเวอร์ชันหลักและหมายเลขรอง <br/>4 ไบต์ถัดไปคือหมายเลขเวอร์ชันหลักและหมายเลขรอง จากรูปด้านบน เราจะเห็นว่าหมายเลขที่สอดคล้องกันตั้งแต่ 00000004h-00000005h คือ 0×0000 ดังนั้น minor_version ของ Class คือ 0×0000 และเนื้อหาที่เกี่ยวข้องจาก 00000006h-00000007h คือ 0×0032 ดังนั้นเวอร์ชัน major_version ของไฟล์ Class คือ 0×0032 ซึ่งเป็นเวอร์ชันหลักและเวอร์ชันรองที่สอดคล้องกับ Class ที่คอมไพล์โดย jdk1.6.0 โดยไม่มี พารามิเตอร์เป้าหมาย
3) จำนวนพูลคงที่ <br/>2 ไบต์ถัดไปแทนจำนวนพูลคงที่ตั้งแต่ 00000008h-00000009h จากรูปด้านบน เราจะทราบได้ว่าค่าของมันคือ 0×0018 ซึ่งก็คือ 24 ในรูปทศนิยม แต่สำหรับ จำเป็นต้องชี้แจงจำนวนพูลคงที่ จำนวนพูลคงที่คือ Constant_pool_count-1 สาเหตุที่ลดลงหนึ่งเนื่องจากดัชนี 0 หมายความว่ารายการข้อมูลในคลาสไม่ได้อ้างอิงค่าคงที่ใดๆ ในพูลคงที่
4) Constant Pool <br/>เรากล่าวไว้ข้างต้นว่ามีค่าคงที่หลายประเภทในกลุ่มค่าคงที่ มาดูค่าคงที่แรกของ TestClass.class กันดีกว่า เรารู้ว่าแต่ละค่าคงที่จะแสดงด้วยตัวระบุแท็กประเภท u1 ประเภทของค่าคงที่ที่ 0000000ah ในภาพด้านบน เนื้อหาคือ 0x0A ซึ่งแปลงเป็นระบบรองคือ 10 จากคำอธิบายข้างต้นของประเภทค่าคงที่ จะเห็นได้ว่าค่าคงที่ที่มีแท็ก 10 คือ Constant_Methodref_info และโครงสร้างของ Constant_Methodref_info ดังแสดงในรูปด้านล่าง:
ในหมู่พวกเขา class_index ชี้ไปที่ค่าคงที่ประเภท CONSTANT_Class_info ในพูลคงที่ จะเห็นได้จากโครงสร้างไฟล์ไบนารีของ TestClass ว่าค่าของ class_index คือ 0×0004 (ที่อยู่คือ 0000000bh-0000000ch) ซึ่งหมายความว่ามันชี้ไปที่ ค่าคงที่ที่สี่
name_and_type_index ชี้ไปที่ค่าคงที่ของประเภท CONSTANT_NameAndType_info ในพูลค่าคงที่ ดังที่เห็นจากรูปด้านบน ค่าของ name_and_type_index คือ 0×0013 ซึ่งหมายความว่าชี้ไปที่ค่าคงที่ที่ 19 ในกลุ่มค่าคงที่
จากนั้น คุณสามารถใช้วิธีเดียวกันเพื่อค้นหาค่าคงที่ทั้งหมดในพูลค่าคงที่ อย่างไรก็ตาม JDK มีเครื่องมือที่สะดวกซึ่งช่วยให้เราสามารถดูค่าคงที่ที่มีอยู่ในพูลค่าคงที่ได้ คุณสามารถรับค่าคงที่ทั้งหมดในพูลคงที่ผ่าน javap -verbose TestClass ภาพหน้าจอมีดังนี้:
จากภาพด้านบน เราจะเห็นได้อย่างชัดเจนว่ามีค่าคงที่ 24 ค่าในกลุ่มค่าคงที่ใน TestClass อย่าลืมค่าคงที่ตัวที่ 0 เนื่องจากค่าคงที่ตัวที่ 0 ใช้เพื่อระบุว่ารายการข้อมูลใน Class ไม่ได้อ้างอิงค่าคงที่ใดๆ ใน สระว่ายน้ำคงที่ จากการวิเคราะห์ข้างต้น เรารู้ว่าวิธีการแสดงค่าคงที่วิธีแรกของ TestClass คือค่าคงที่ที่สี่ที่ชี้โดย class_index คือ java/lang/Object และค่าคงที่ที่ 19 ที่ชี้โดย name_and_type_index คือ <init>:()V จะเห็นได้ที่นี่ว่าค่าคงที่แรกที่แสดงถึงวิธีการแสดงถึงวิธีการสร้างอินสแตนซ์ที่สร้างโดยคอมไพเลอร์ Java ค่าคงที่อื่นๆ ในกลุ่มค่าคงที่สามารถวิเคราะห์ได้ในลักษณะเดียวกัน ตกลง หลังจากวิเคราะห์พูลคงที่แล้ว มาวิเคราะห์ access_flags กันต่อไป
5) u2 access_flags แสดงถึงข้อมูลการเข้าถึงเกี่ยวกับคลาสหรืออินเทอร์เฟซ ตัวอย่างเช่น Class แสดงถึงว่าเป็นคลาสหรืออินเทอร์เฟซ ไม่ว่าจะเป็นสาธารณะ คงที่ สุดท้าย ฯลฯ ความหมายของค่าสถานะการเข้าถึงเฉพาะได้ถูกกล่าวถึงไปแล้ว ลองมาดูค่าสถานะการเข้าถึงของ TestClass กัน แฟล็กการเข้าถึงของคลาสมาจาก 0000010dh-0000010e และค่าคือ 0×0021 ตามบิตแฟล็กของแฟล็กการเข้าถึงต่างๆ ที่กล่าวถึงก่อนหน้านี้ เราสามารถรู้ได้: 0×0021=0×0001|0×0020 นั่นคือ ACC_PUBLIC และ ACC_SUPER เป็น True, ACC_PUBLIC เข้าใจง่ายและ ACC_SUPER เป็นแฟล็กที่จะดำเนินการโดยคลาสที่คอมไพล์หลังจาก jdk1.2
6) u2 this_class แสดงถึงค่าดัชนีของคลาสซึ่งใช้เพื่อแสดงชื่อแบบเต็มของคลาส ค่าดัชนีของคลาสดังแสดงในรูปด้านล่าง:
ดังที่เห็นได้ชัดเจนจากรูปด้านบน ค่าดัชนีคลาสคือ 0×0003 ซึ่งสอดคล้องกับค่าคงที่ที่สามของพูลค่าคงที่ จากผลลัพธ์ของ javap เรารู้ว่าค่าคงที่ที่สามนั้นเป็นค่าคงที่ของประเภท CONSTANT_Class_info ซึ่งเราสามารถรู้รายละเอียดทั้งหมดของคลาสได้ ชื่อที่ผ่านการรับรองคือ: com/ejushang/TestClass /TestClass
7) u2 super_class แสดงถึงค่าดัชนีของคลาสพาเรนต์ของคลาสปัจจุบัน ค่าดัชนีชี้ไปที่ค่าคงที่ประเภท CONSTANT_Class_info ในพูลคงที่ ค่าดัชนีของคลาสพาเรนต์ดังแสดงในรูปด้านล่าง 0×0004 ตรวจสอบค่าคงที่สี่ค่าแรกของพูลคงที่ จะเห็นได้ว่าชื่อแบบเต็มของคลาสหลักของ TestClass คือ: java/lang/Object
8) interfaces_count และ interfaces[interfaces_count] แทนจำนวนอินเทอร์เฟซและแต่ละอินเทอร์เฟซเฉพาะ จำนวนอินเทอร์เฟซและอินเทอร์เฟซของ TestClass ดังแสดงในรูปด้านล่าง โดยที่ 0×0001 หมายความว่า จำนวนอินเทอร์เฟซคือ 1 และ 0× 0005 หมายถึงดัชนีของอินเทอร์เฟซในค่าพูลคงที่ ค้นหาค่าคงที่ที่ห้าในพูลคงที่ ประเภทคือ CONSTANT_Class_info และค่าของมันคือ: com/ejushang/TestClass/Super
9) fields_count และ field_info , fields_count แสดงถึงจำนวนของตาราง field_info ในคลาส และ field_info แสดงถึงตัวแปรอินสแตนซ์และตัวแปรคลาสของคลาส ควรสังเกตไว้ที่นี่ว่า field_info ไม่รวมฟิลด์ที่สืบทอดมาจากคลาสพาเรนต์ field_info ดังแสดงในรูปด้านล่าง:
ในหมู่พวกเขา access_flags แสดงถึงแฟล็กการเข้าถึงของฟิลด์ เช่น สาธารณะ ส่วนตัว ได้รับการป้องกัน คงที่ สุดท้าย ฯลฯ ค่าของ access_flags ดังแสดงในรูปด้านล่าง:
ในหมู่พวกเขา name_index และ descriptor_index เป็นทั้งค่าดัชนีของพูลคงที่ซึ่งตามลำดับแสดงถึงชื่อของฟิลด์และ descriptor ของฟิลด์ ชื่อของฟิลด์นั้นง่ายต่อการเข้าใจ แต่จะเข้าใจ descriptor ของฟิลด์ได้อย่างไร สนาม? ในความเป็นจริง ในข้อกำหนด JVM ตัวอธิบายฟิลด์จะถูกระบุดังแสดงในรูปต่อไปนี้:
ในหมู่พวกเขา ทุกคนต้องให้ความสนใจกับบรรทัดสุดท้ายของรูปภาพด้านบน ซึ่งแสดงถึง descriptor ของอาร์เรย์หนึ่งมิติ descriptor สำหรับ String[][] จะเป็น [[ Ljava/lang/String และคำอธิบายสำหรับ int[][] สัญลักษณ์คือ [[I. Attributes_count และ Attributes_info ต่อไปนี้แสดงถึงจำนวนตารางแอ็ตทริบิวต์และตารางแอ็ตทริบิวต์ตามลำดับ ลองใช้ TestClass ข้างต้นเป็นตัวอย่าง และดูตารางภาคสนามของ TestClass
ขั้นแรก มาดูจำนวนฟิลด์ใน TestClass ดังแสดงในรูปด้านล่าง:
ดังที่เห็นได้จากภาพด้านบน TestClass มีสองช่อง เมื่อดูซอร์สโค้ดของ TestClass เราจะเห็นว่ามีเพียงสองช่องเท่านั้น ต่อไปเรามาดูช่องแรกกันดีกว่า private int staticVar ซึ่งการแทนค่าไบนารี่ในไฟล์ Class มีดังต่อไปนี้:
ในหมู่พวกเขา 0x001A แสดงถึงค่าสถานะการเข้าถึง เมื่อดูที่ตาราง access_flags เราจะรู้ได้ว่ามันคือ ACC_PRIVATE, ACC_STATIC, ACC_FINAL ถัดไป 0×0006 และ 0×0007 แสดงถึงค่าคงที่ที่ 6 และ 7 ในกลุ่มค่าคงที่ตามลำดับ เมื่อดูที่พูลคงที่ เราจะรู้ได้ว่าค่าของพวกมันคือ: staticVar และ I โดยที่ staticVar คือชื่อฟิลด์ และ I คือตัวอธิบายฟิลด์ จากคำอธิบายข้างต้น สิ่งที่ฉันอธิบายคือตัวแปรประเภท int ต่อไป 0×0001 แทนจำนวนตารางแอตทริบิวต์ในตารางฟิลด์ staticVar จากรูปด้านบน จะเห็นได้ว่ามีตารางแอตทริบิวต์ 1 ตารางที่สอดคล้องกัน ไปที่ฟิลด์ staticVar 0×0008 แสดงถึงค่าคงที่ที่ 8 ในกลุ่มค่าคงที่ คุณจะเห็นว่าแอตทริบิวต์นี้เป็นแอตทริบิวต์ ConstantValue และรูปแบบของแอตทริบิวต์ ConstantValue ดังแสดงในรูปด้านล่าง:
ในหมู่พวกเขาattribute_name_indexแสดงดัชนีพูลคงที่ของชื่อแอ็ตทริบิวต์ ในตัวอย่างนี้ คือ ConstantValue ของ ConstantValue มีความยาวคงที่เป็น 2 และ ConstantValue_index แสดงถึงการอ้างอิงในพูลค่าคงที่ ในตัวอย่างนี้ คือ 0 ×0009 คุณสามารถดูค่าคงที่ที่ 9 ได้ ซึ่งหมายถึงค่าคงที่ประเภท CONSTANT_Integer_info ซึ่งมีค่าเป็น 0
ต้องบอกว่า private static สุดท้าย int staticVar=0 เรามาพูดถึง private int instanceVar=0 ของ TestClass กัน ในตัวอย่างนี้ การแสดงไบนารี่ของ instanceVar ดังแสดงในรูปด้านล่าง:
ในจำนวนนั้น 0×0002 หมายความว่าเครื่องหมายการเข้าถึงคือ ACC_PRIVATE, 0x000A หมายถึงชื่อของฟิลด์ ซึ่งชี้ไปยังค่าคงที่ที่ 10 ในพูลคงที่ คุณจะรู้ได้ว่าชื่อฟิลด์คือ instanceVar และ 0× 0007 แสดงถึงคำอธิบายของฟิลด์ ซึ่งชี้ไปที่ค่าคงที่ที่ 7 ในกลุ่มค่าคงที่ คุณจะทราบได้ว่าค่าคงที่ที่ 7 คือ I ซึ่งแสดงถึงประเภทของ instanceVar สุดท้าย 0×0000 แสดงถึงค่านั้น จำนวนตารางแอตทริบิวต์คือ 0 .
10) Methods_count และ Methods_info โดยที่ Methods_count แสดงถึงจำนวนวิธี และ Methods_info แสดงถึงตารางเมธอด โดยที่โครงสร้างของตารางเมธอดดังแสดงในรูปด้านล่าง:
ดังที่เห็นได้จากรูปด้านบน โครงสร้างของ method_info และ field_info มีความคล้ายคลึงกันมาก บิตแฟล็กและค่าทั้งหมดของ access_flag ในตารางเมธอดดังแสดงในรูปด้านล่าง:
ในหมู่พวกเขา name_index และ descriptor_index เป็นตัวแทนของชื่อและคำอธิบายของวิธีการ และเป็นดัชนีที่ชี้ไปยังพูลคงที่ตามลำดับ ที่นี่เราจำเป็นต้องอธิบายตัวอธิบายวิธีการ โครงสร้างของตัวอธิบายวิธีการคือ: (รายการพารามิเตอร์) ค่าส่งคืน ตัวอย่างเช่น ตัวอธิบายของ public int instanceMethod(int param) คือ: (I) I ซึ่งหมายความว่ามันมี int พารามิเตอร์ประเภท และค่าที่ส่งคืนยังเป็นวิธีการประเภท int ถัดไปคือจำนวนแอตทริบิวต์และตารางแอตทริบิวต์ แตกต่าง. ต่อไป มาดูการแสดงไบนารี่ของตารางเมธอดโดยใช้ TestClass ก่อนอื่น มาดูจำนวนตารางวิธีการกันก่อน ภาพหน้าจอจะเป็นดังนี้:
ดังที่เห็นจากรูปด้านบน จำนวนตารางเมธอดคือ 0×0002 ซึ่งหมายความว่ามีสองวิธี ต่อไปเรามาวิเคราะห์วิธีแรกกันก่อน ลองดูที่ access_flag, name_index, descriptor_index ของวิธีแรกของ TestClass ภาพหน้าจอมีดังนี้:
จากรูปด้านบน เราจะรู้ได้ว่า access_flags คือ 0×0001 จากคำอธิบายข้างต้นของค่าสถานะ access_flags เราจะเห็นว่าค่าของ access_flags ของเมธอดคือ ACC_PUBLIC และ name_index คือ 0x000B ค่าคงที่ที่ 11 เมื่อรู้ว่าชื่อของเมธอดคือ <init> 0x000C หมายถึง descriptor_index หมายถึงค่าคงที่ที่ 12 ในพูลค่าคงที่ และค่าของมันคือ ()V ซึ่งหมายความว่าเมธอด <init> ไม่มีพารามิเตอร์และค่าที่ส่งคืน ในความเป็นจริงนี่คือวิธีการสร้างอินสแตนซ์ของคอมไพเลอร์ที่สร้างขึ้นโดยอัตโนมัติ 0×0001 ถัดไปบ่งชี้ว่าตารางวิธีการของวิธี <init> มี 1 แอตทริบิวต์ ภาพหน้าจอของแอตทริบิวต์มีดังนี้:
ดังที่เห็นได้จากรูปด้านบน ค่าคงที่ในกลุ่มค่าคงที่ที่สอดคล้องกับ 0x000D คือ Code ซึ่งแสดงถึงแอตทริบิวต์ Code ของเมธอด ดังนั้น ทุกคนควรเข้าใจว่าโค้ดของเมธอดถูกจัดเก็บไว้ในแอตทริบิวต์ Code ในแอตทริบิวต์ ตารางในตารางวิธีการของไฟล์คลาส ต่อไปเราจะวิเคราะห์แอตทริบิวต์ Code โครงสร้างของแอตทริบิวต์ Code จะแสดงในรูปด้านล่าง:
ในบรรดาแอตทริบิวต์เหล่านี้ คุณลักษณะ_name_index ชี้ไปที่ค่าคงที่ซึ่งมีค่าเป็นรหัสในพูลค่าคงที่ และความยาวของแอตทริบิวต์_ความยาวจะระบุความยาวของตารางแอตทริบิวต์รหัส (ควรสังเกตว่าความยาวไม่รวมความยาว 6 ไบต์ของแอตทริบิวต์ชื่อแอตทริบิวต์และแอตทริบิวต์_ความยาว ).
max_stack แสดงถึงความลึกของสแต็กสูงสุด เครื่องเสมือนจะจัดสรรความลึกของตัวถูกดำเนินการในเฟรมสแต็กตามค่านี้ขณะรันไทม์ และ max_locals แสดงถึงพื้นที่เก็บข้อมูลของตารางตัวแปรโลคัล
หน่วยของ max_locals คือ slot ซึ่งเป็นหน่วยที่เล็กที่สุดสำหรับเครื่องเสมือนในการจัดสรรหน่วยความจำสำหรับตัวแปรในเครื่อง ณ รันไทม์ ชนิดข้อมูลที่ไม่เกินประเภท 32 บิต เช่น ไบต์, ถ่าน, int ฯลฯ จะครอบครอง 1 ช่องในขณะที่สองเท่าและยาว ชนิดข้อมูล 64 บิตจำเป็นต้องจัดสรร 2 สล็อต นอกจากนี้ ค่าของ max_locals ยังไม่ใช่ผลรวมของหน่วยความจำที่ตัวแปรโลคัลทั้งหมดต้องการ เนื่องจากสล็อตสามารถนำมาใช้ซ้ำได้ เมื่อตัวแปรโลคัลเกินขอบเขต ตัวแปรโลคัล The ช่องที่ถูกครอบครองจะถูกนำมาใช้ซ้ำ
code_length แทนจำนวนคำสั่ง bytecode และ code แทนคำสั่ง bytecode จากรูปด้านบน เราจะทราบได้ว่าประเภทของโค้ดคือ u1 ค่าของประเภท u1 คือ 0×00-0xFF และทศนิยมที่สอดคล้องกันคือ 0- 255 ปัจจุบัน ข้อกำหนดเฉพาะของเครื่องเสมือนได้กำหนดคำสั่งไว้มากกว่า 200 คำสั่ง
ข้อยกเว้น _table_length และ ข้อยกเว้น _table ตามลำดับแสดงถึงข้อมูลข้อยกเว้นที่สอดคล้องกับวิธีการ
Attributes_count และ Attribute_info แสดงถึงจำนวนแอ็ตทริบิวต์และตารางแอ็ตทริบิวต์ในแอ็ตทริบิวต์ Code ตามลำดับ จะเห็นได้ว่าตารางแอ็ตทริบิวต์มีความยืดหยุ่นมากในโครงสร้างไฟล์ของ Class แอตทริบิวต์ตารางและรหัส
ต่อไป เราจะวิเคราะห์ตัวอย่างข้างต้นต่อไป จากภาพหน้าจอของแอตทริบิวต์ Code ของเมธอด init ด้านบน เราจะเห็นว่าความยาวของตารางแอตทริบิวต์คือ 0×00000026 ค่าของ max_stack คือ 0×0002 และค่า ของ max_locals คือ 0× 0001 ความยาวของ code_length คือ 0x0000000A จากนั้น 00000149h- 00000152h คือ bytecode ต่อไป ความยาวของException_table_lengthคือ 0×0000 และค่าของattribute_countคือ 0×0001 ค่าของ 00000157h-00000158h คือ 0x000E ซึ่งแสดงถึงชื่อของแอ็ตทริบิวต์ในพูลคงที่ เพื่อให้ได้อันที่ 14 ค่าคงที่คือ LineNumberTable, LineNu mberTable ใช้เพื่ออธิบายความสอดคล้องระหว่างหมายเลขบรรทัดซอร์สโค้ด Java และหมายเลขบรรทัด bytecode ซึ่งไม่ใช่แอตทริบิวต์ที่จำเป็นในขณะรันไทม์ หากคุณยกเลิกการสร้างข้อมูลนี้ผ่านพารามิเตอร์คอมไพเลอร์ -g:none จะได้รับผลกระทบมากที่สุด เมื่อมีข้อยกเว้นเกิดขึ้น ไม่สามารถแสดงหมายเลขบรรทัดข้อผิดพลาดบนสแต็ก และไม่สามารถตั้งค่าเบรกพอยต์ตามซอร์สโค้ดในระหว่างการดีบัก ต่อไป มาดูโครงสร้างของ LineNumberTable ดังที่แสดงด้านล่าง:
ในบรรดาแอตทริบิวต์เหล่านี้ มีการกล่าวถึงattribute_name_index และแสดงถึงดัชนีของพูลคงที่ คุณลักษณะ_ความยาวแสดงถึงความยาวของแอตทริบิวต์ และตาราง start_pc และ line_number แสดงถึงหมายเลขบรรทัดของโค้ดไบต์และหมายเลขบรรทัดของซอร์สโค้ด สตรีมไบต์ของคุณสมบัติ LineNumberTable ในตัวอย่างนี้ดังแสดงด้านล่าง:
หลังจากวิเคราะห์วิธีแรกของ TestClass ข้างต้นแล้ว เราก็สามารถวิเคราะห์วิธีที่สองของ TestClass ได้ในลักษณะเดียวกัน ภาพหน้าจอจะเป็นดังนี้:
ในหมู่พวกเขา access_flags คือ 0×0001, name_index คือ 0x000F และ descriptor_index คือ 0×0010 เมื่อดูที่พูลคงที่ คุณจะรู้ได้ว่าวิธีนี้เป็นวิธีการ int instanceMethod (int param) สาธารณะ ด้วยวิธีการที่คล้ายกับข้างต้น เราสามารถรู้ได้ว่าแอตทริบิวต์ Code ของ instanceMethod ดังแสดงในรูปด้านล่าง:
สุดท้ายนี้ มาวิเคราะห์คุณลักษณะของไฟล์ Class กันดีกว่า จาก 00000191h-00000199h เป็นตารางคุณลักษณะในไฟล์ Class โดยที่ 0×0011 แสดงถึงชื่อของคุณลักษณะ มาดูโครงสร้างของ SourceFile กันตามรูปนี้ครับ
ในหมู่พวกเขาattribute_lengthคือความยาวของแอตทริบิวต์ และsourcefile_indexชี้ไปที่ค่าคงที่ในกลุ่มค่าคงที่ซึ่งค่าเป็นชื่อของไฟล์ซอร์สโค้ด ในตัวอย่างนี้ ภาพหน้าจอของแอตทริบิวต์ SourceFile จะเป็นดังนี้:
ในบรรดาแอตทริบิวต์เหล่านี้คือ 0×00000002 ซึ่งหมายถึงความยาวคือ 2 ไบต์ และค่าของ sourcefile_index คือ 0×0012 เมื่อดูค่าคงที่ที่ 18 ในพูลคงที่ คุณจะรู้ได้ว่าชื่อของไฟล์ซอร์สโค้ดคือ TestClass .java
สุดท้ายนี้ผมหวังว่าเพื่อนๆ ที่สนใจเรื่องเทคโนโลยีจะสามารถสื่อสารกันได้มากขึ้น Weibo ส่วนตัว: (http://weibo.com/xmuzyq)