مرحبا بالجميع! تم إعداد ترجمة للمقال خصيصًا لطلاب دورة Java Developer .
نواصل الحديث عن كيفية عمل Java Virtual Machine داخليًا. في
المقالة السابقة (
الأصل باللغة الإنجليزية ) ، درسنا النظام الفرعي لتحميل الصف. في هذه المقالة سوف نتحدث عن هيكل الملفات الصفية.
كما نعلم بالفعل ، يتم تجميع جميع الشفرات المصدرية المكتوبة بلغة برمجة Java أولاً إلى رمز
javac
باستخدام برنامج التحويل البرمجي
javac
، الذي يعد جزءًا من Java Development Kit. يتم تخزين bytecode في ملف ثنائي في ملف فئة خاصة. ثم يتم تحميل ملفات الفئة هذه ديناميكيًا (إذا لزم الأمر) في الذاكرة بواسطة أداة تحميل الفئة (ClassLoader).
الشكل - تجميع شفرة مصدر جافايتم تصنيف كل ملف
.java
في ملف
.class
واحد على الأقل. لكل فئة ، واجهة ، والوحدة النمطية المعرفة في التعليمات البرمجية المصدر ، يتم إنشاء ملف
.class
واحد. وهذا ينطبق أيضا على واجهات والفئات المتداخلة.
ملاحظة - للبساطة ، سيتم
.class
الملفات ذات الملحق
.class
"ملفات فئة".
دعنا نكتب برنامج بسيط.
public class ClassOne{ public static void main(String[] args){ System.out.println("Hello world"); } static class StaticNestedClass{ } } class ClassTwo{ } interface InterfaceOne{ }
يؤدي تشغيل
javac
لهذا الملف إلى الملفات التالية.
ClassOne$StaticNestedClass.class ClassOne.class ClassTwo.class InterfaceOne.class
كما ترون ، يتم إنشاء ملف فئة منفصلة لكل فئة وواجهة.
ما هو داخل ملف الفصل؟
ملف الفصل في تنسيق ثنائي. عادة ما يتم كتابة المعلومات الموجودة فيه دون المسافة البادئة بين أجزاء متتالية من المعلومات ، كل شيء محاذي للحدود بايت. تتم كتابة جميع قيم 16 بت و 32 بت باستخدام اثنين أو أربعة بايت 8 بت متتالية.
يحتوي ملف الفصل على المعلومات التالية.
رقم السحر ، التوقيع . البايت الأربع الأولى من كل ملف فئة دائماً
0xCAFEBABE
. تحدد هذه البايتات الأربعة ملف فئة Java.
نسخة الملف. تحتوي البايتات الأربعة التالية على الإصدارات الرئيسية والثانوية من الملف. تحدد هذه الأرقام معًا إصدار تنسيق ملف الفصل. إذا كان ملف الفصل يحتوي على إصدار رئيسي رئيسي من M و m ثانوي ، فسنقوم بتعيين هذا الإصدار على أنه Mm
كل JVM لها قيود على الإصدارات المدعومة من ملفات الفئة. على سبيل المثال ، يدعم Java 11 الإصدارات الرئيسية من 45 إلى 55 ، و Java 12 - من 45 إلى 56.
مجموعة من الثوابت. جدول بنيات تمثل ثوابت السلسلة وأسماء الفئات والواجهات والحقول والأساليب والثوابت الأخرى الموجودة في بنية ClassFile وبنيتها الأساسية. يبدأ كل عنصر تجمع ثابت بعلامة أحادية البايت تحدد نوع الثابت. اعتمادًا على نوع الثابت ، قد تكون البايتات التالية قيمة ثابتة فورية أو مرجعًا إلى عنصر آخر في التجمع.
أعلام الوصول. قائمة العلامات التي تشير إلى الفصل هي إما واجهة ، عامة أو خاصة ، فئة نهائية أم لا. يتم وصف إشارات مختلفة مثل
ACC_PUBLIC
و
ACC_FINAL
و
ACC_INTERFACE
و
ACC_ENUM
، إلخ في مواصفات Java Virtual Machine.
هذه الفئة. رابط إلى الإدخال في التجمع المستمر.
الطبقة العليا. رابط إلى الإدخال في التجمع المستمر.
الواجهات. عدد واجهات تنفيذها من قبل الطبقة.
عدد الحقول. عدد الحقول في الفصل أو الواجهة.
المجال. بعد عدد الحقول ، يتبع جدول بنيات ذات طول متغير. واحد لكل حقل مع وصف لنوع الحقل واسم (مع الإشارة إلى مجموعة الثوابت).
عدد الطرق. عدد الطرق في الفصل أو الواجهة. يتضمن هذا الرقم فقط الطرق التي تم تعريفها بشكل صريح في الفصل ، دون الطرق الموروثة من الفئات الفائقة.
الأساليب. التالي هي الأساليب نفسها. لكل طريقة ، يتم احتواء المعلومات التالية: واصف الطريقة (نوع الإرجاع وقائمة الوسيطة) ، وعدد الكلمات اللازمة للمتغيرات المحلية للأسلوب ، والحد الأقصى لعدد الكلمات المكدس اللازمة لأسلوب معامِلة الطريقة ، وجدول الاستثناء الذي تم اكتشافه بواسطة الطريقة ، ورموز الطريقة والجدول أرقام الأسطر.
عدد الصفات. عدد السمات في هذه الفئة أو الواجهة أو الوحدة النمطية.
الصفات. عدد السمات يتبعه جداول أو هياكل متغيرة الطول تصف كل سمة. على سبيل المثال ، هناك دائمًا سمة "SourceFile". يحتوي على اسم الملف المصدر الذي تم تحويل ملف الفئة منه.
على الرغم من أن ملف الفصل الدراسي لا يمكن قراءته مباشرة من قبل الإنسان ، إلا أن هناك أداة في JDK تسمى
javap تعرض محتوياته بتنسيق مناسب.
دعنا نكتب برنامج جافا بسيط كما هو موضح أدناه.
package bytecode; import java.io.Serializable; public class HelloWorld implements Serializable, Cloneable { public static void main(String[] args) { System.out.println("Hello World"); } }
دعنا
javap
هذا البرنامج مع
javac
، والذي سينشئ ملف
HelloWorld.class
، ونستخدم
javap
لعرض ملف
HelloWorld.class
. يؤدي تشغيل
javap
باستخدام الخيار
-v (verbose)
لـ
HelloWorld.class
إلى النتيجة التالية:
Classfile /Users/apersiankite/Documents/code_practice/java_practice/target/classes/bytecode/HelloWorld.class Last modified 02-Jul-2019; size 606 bytes MD5 checksum 6442d93b955c2e249619a1bade6d5b98 Compiled from "HelloWorld.java" public class bytecode.HelloWorld implements java.io.Serializable,java.lang.Cloneable minor version: 0 major version: 55 flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #5 // bytecode/HelloWorld super_class: #6 // java/lang/Object interfaces: 2, fields: 0, methods: 2, attributes: 1 Constant pool: #1 = Methodref #6.#22
هنا يمكنك أن ترى أن الفصل عام وله 37 إدخال في المجموعة الثابتة. هناك سمة واحدة (SourceFile أدناه) ، تنفذ الفئة واجهات اثنين (Serializable ، Cloneable) ، وليس لديها حقول ، وهناك طريقتان.
ربما لاحظت وجود طريقة رئيسية ثابتة واحدة فقط في التعليمات البرمجية المصدر ، ولكن يشير ملف الفصل إلى وجود طريقتين. تذكر المُنشئ الافتراضي - هذا مُنشئ بلا وسيطة يُضاف من قِبل برنامج التحويل البرمجي
javac
، والذي يكون رمزه الثانوي مرئيًا أيضًا في الإخراج. البنائين تعتبر أساليب.
يمكنك قراءة المزيد عن japap
هنا .
نصيحة : يمكنك أيضًا استخدام javap لترى كيف تختلف lambdas عن الطبقات الداخلية المجهولة.