צפה ב- Bytecode של קובץ כיתה ב- Java

1. סקירה כללית

ניתוח Bytecode הוא נוהג נפוץ בקרב מפתחי Java מסיבות רבות, כמו למצוא בעיות בקוד, פרופיל קוד וחיפוש שיעורים עם הערות ספציפיות.

במאמר זה נחקור דרכים להציג את קוד הביצה של קובץ מחלקה ב- Java.

2. מהו ה- Bytecode?

Bytecode הוא ייצוג ביניים של תוכנית Java, המאפשר ל- JVM לתרגם תוכנית להוראות הרכבה ברמת המכונה.

כאשר תוכנית Java מורכבת, bytecode נוצר בצורה של .מעמד קוֹבֶץ. זֶה .מעמד הקובץ מכיל הוראות שאינן ניתנות להפעלה ומסתמך על פרשנות JVM.

3. שימוש javap

שורת הפקודה של Java מגיעה עם ה- javap כלי המציג מידע על השדות, הבנאים והשיטות של קובץ כיתה.

בהתבסס על האפשרויות המשמשות, הוא יכול לפרק כיתה ולהראות את ההוראות המרכיבות את קוד ה- Java bytecode.

3.1. javap

בואו נשתמש ב- javap פקודה כדי להציג את קוד הביס של הנפוץ ביותר לְהִתְנַגֵד מעמד:

$ javap java.lang.Object

פלט הפקודה יציג את ההרכב המינימלי של ה- לְהִתְנַגֵד מעמד:

מחלקה ציבורית java.lang.Object {java.lang.Object ציבורי (); גמר ציבורי יליד java.lang.Class getClass (); יליד ציבור int hashCode (); שווה ציבורית בוליאנית (java.lang.Object); שיבוט מקורי מוגן java.lang.Object () זורק java.lang.CloneNotSupportedException; java.lang.String toString () ציבורי; הודעה על חלל ציבורי סופי ציבורי (); יליד חלל סופי ציבורי notifyAll (); גמר ציבורי יליד חלל (ארוך) זורק java.lang.InterruptedException; המתנה בטלה סופית ציבורית (ארוכה, int) זורקת java.lang.InterruptedException; המתנה בטלה ציבורית סופית () זורקת java.lang.InterruptedException; חלל מוגן לסיים () זורק java.lang.Throwable; סטטי {}; }

כברירת מחדל, פלט קוד ה- byt לא יכיל שדות / שיטות עם פרטי שינוי גישה.

3.2. javap-p

כדי להציג את כל הכיתות והחברים, נוכל להשתמש ב- -p טַעֲנָה:

מחלקה ציבורית java.lang.Object {java.lang.Object ציבורי (); פרטי רישום חלל סטטי פרטי ילידי (); גמר ציבורי יליד java.lang.Class getClass (); יליד ציבור int hashCode (); שווה ציבורית בוליאנית (java.lang.Object); שיבוט מקורי מוגן java.lang.Object () זורק java.lang.CloneNotSupportedException; // ...}

כאן, אנו יכולים לראות א פְּרָטִי שיטה registerNatives מוצג גם בקוד-התיקיה של ה- לְהִתְנַגֵד מעמד.

3.3. javap-v

באופן דומה, אנו יכולים להשתמש ב- -v טיעון להצגת מידע רבתי כמו גודל מחסנית וטיעונים לשיטות לְהִתְנַגֵד מעמד:

צנצנת Classfile: file: /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/rt.jar! /Java/lang/Object.class שונתה לאחרונה ב -15 במרץ 2017; גודל 1497 בתים MD5 בדיקת 5916745820b5eb3e5647da3b6cc6ef65 מחובר מתוך "Object.java" מחלקה ציבורית java.lang.Object גרסה מינורית: 0 גרסה עיקרית: 52 דגלים: ACC_PUBLIC, ACC_SUPER בריכה קבועה: # 1 = Class # 49 // java / lang / StringBuilder / / ... {ציבורי java.lang.Object (); מתאר: () דגלי V: קוד ACC_PUBLIC: stack = 0, local = 1, args_size = 1 0: return LineNumberTable: line 37: 0 public final final java.lang.Class getClass (); מתאר: () Ljava / lang / Class; דגלים: ACC_PUBLIC, ACC_FINAL, ACC_NATIVE חתימה: # 26 // () Ljava / lang / Class; // ...} SourceFile: "Object.java"

3.4. javap

וגם ה javap הפקודה מאפשרת לפרק את כל מחלקת Java באמצעות ה- טַעֲנָה:

הורכב מהמחלקה הציבורית "Object.java" java.lang.Object {java.lang.Object ציבורי (); קוד: 0: להחזיר שווים בוליאניים ציבוריים (java.lang.Object); קוד: 0: aload_0 1: aload_1 2: if_acmpne 9 5: iconst_1 6: goto 10 9: iconst_0 10: ireturn מוגן java.lang.Object שיבוט () זורק java.lang.CloneNotSupportedException; // ...}

יתר על כן, javap הפקודה מאפשרת לנו לבדוק את פרטי המערכת, הקבועים וחתימות הסוג הפנימי באמצעות ארגומנטים שונים.

אנו יכולים לרשום את כל הטיעונים הנתמכים על ידי javap באמצעות הפקודה -עֶזרָה טַעֲנָה.

עכשיו, כשראינו פתרון של שורת פקודה של Java לצפייה בקוד-הקובץ של קובץ מחלקה, בואו נבחן כמה ספריות-מניפולציה של קוד-קוד.

4. שימוש ב- ASM

ASM היא מסגרת מניפולציה וניתוח פופולרית מוכוונת ביצועים ורמה נמוכה של Java.

4.1. להכין

ראשית, בואו נוסיף את האחרונה asm ו asm-util תלות Maven שלנו pom.xml:

 org.ow2.asm asm 8.0.1 org.ow2.asm asm-util 8.0.1 

4.2. צפה ב- Bytecode

ואז נשתמש ב- ClassReader ו TraceClassVisitor לצפייה בקוד התצוגה של לְהִתְנַגֵד מעמד:

נסה את {ClassReader reader = ClassReader חדש ("java.lang.Object"); StringWriter sw = חדש StringWriter (); TraceClassVisitor tcv = TraceClassVisitor חדש (PrintWriter חדש (System.out)); reader.accept (tcv, 0); } לתפוס (IOException e) {e.printStackTrace (); }

כאן נציין כי ה- TraceClassVisitor אובייקט דורש את PrintWriter אובייקט לחילוץ וייצור קוד הבתים:

// גרסת מחלקה 52.0 (52) // דגלי גישה 0x21 מחלקה ציבורית java / lang / Object {// מחובר מ: Object.java // דגלי גישה 0x1 ציבוריים () V L0 LINENUMBER 37 L0 RETURN MAXSTACK = 0 MAXLOCALS = 1 / / access flags 0x101 public native hashCode () I // access flags 0x1 public שווה (Ljava / lang / Object;) Z L0 LINENUMBER 149 LO ALOAD 0 ALOAD 1 IF_ACMPNE L1 ICONST_1 GOTO L2 L1 // ...}

5. שימוש ב- BCEL

ספריית הנדסת Byte Code, הידועה בכינויו Apache Commons BCEL, מספקת דרך נוחה ליצור / לתפעל קבצי Java בכיתה.

5.1. תלות של Maven

כרגיל, בואו נוסיף את האחרונה bcel תלות Maven שלנו pom.xml:

 org.apache.bcel bcel 6.5.0 

5.2. לפרק את הכיתה ולהציג את Bytecode

ואז נוכל להשתמש ב- מאגר בכיתה לייצר את JavaClass לְהִתְנַגֵד:

נסה את {JavaClass objectClazz = Repository.lookupClass ("java.lang.Object"); System.out.println (objectClazz.toString ()); } לתפוס (ClassNotFoundException e) {e.printStackTrace (); }

הנה, השתמשנו ב- toString שיטה על objectClazz התנגד לראות קוד בתבנית תמציתית:

מחלקה ציבורית java.lang.Object שם קובץ java.lang.Object מלוקט מגרסת המהדר Object.java 52.0 דגלי גישה 33 מאגר קבוע 78 כניסות ACC_SUPER דגל נכון תכונות (ים): SourceFile: Object.java 14 שיטות: חלל ציבורי () פרטי רישום חלל סטטי יליד ילידים () ציבורי יליד ציבורי Class ClassClass () [חתימה: () Ljava / lang / Class;] יליד ציבור int hashCode () בוליאני ציבורי שווה (Object arg1) שיבוט אובייקט מקורי מוגן () זורק חריגים: java.lang .CloneNotSupportedException ציבורי מחרוזת toString () ציבורי חלופי סופי ציבורי הודעה () // ...

יתר על כן, JavaClass בכיתה מספקת שיטות כמו getConstantPool, getFields, ו getMethods לצפייה בפרטי המעמד המפורק.

assertEquals (objectClazz.getFileName (), "java.lang.Object"); assertEquals (objectClazz.getMethods (). אורך, 14); assertTrue (objectClazz.toString (). מכיל ("java.lang.Object בכיתה ציבורית")); 

בדומה לכך, מַעֲרֶכֶת* שיטות זמינות למניפולציה של קוד-byte.

6. שימוש ב- Javassist

כמו כן, אנו יכולים להשתמש ב- ג'אווסיסט (עוזר תכנות Java) ספרייה המספקת ממשקי API ברמה גבוהה לצפייה / מניפולציה של קוד ה- Java bytecode.

6.1. תלות של Maven

ראשית, נוסיף את האחרונה יוואסיסט תלות Maven שלנו pom.xml:

 org.javassist javassist 3.27.0-GA 

6.2. לִיצוֹר ClassFile

ואז נוכל להשתמש ב- ClassPool ו ClassFile שיעורים ליצירת מחלקת Java:

נסה את {ClassPool cp = ClassPool.getDefault (); ClassFile cf = cp.get ("java.lang.Object"). GetClassFile (); cf.write (DataOutputStream חדש (FileOutputStream חדש ("Object.class"))); } לתפוס (NotFoundException e) {e.printStackTrace (); }

הנה, השתמשנו ב- לִכתוֹב השיטה, המאפשרת לנו לכתוב את קובץ הכיתה באמצעות ה- DataOutputStream לְהִתְנַגֵד:

// מחובר מ- Object.java (גרסה 1.8: 52.0, סופר סיבית) java.lang.Object בכיתה ציבורית {// מתאר השיטה מספר 19 () V // מחסנית: 0, מקומיים: אובייקט ציבורי אחד (); 0 החזרת מספרי שורות: [pc: 0, line: 37] // מתאר שיטה מספר 19 () V register static native void registerNatives (); // מתאר השיטה מספר 24 () Ljava / lang / Class; // חתימה: () Ljava / lang / Class; גמר ציבורי יליד java.lang.Class getClass (); // מתאר שיטה מס '28 () אני ציבורי יליד hashCode (); // ...

כמו כן, מושא ה ClassFile מחלקה מספקת גישה לבריכה המתמדת, לשדות ולשיטות:

assertEquals (cf.getName (), "java.lang.Object"); assertEquals (ראה getMethods (). גודל (), 14);

7. ג'קלאסליב

בנוסף, אנו יכולים להשתמש בתוסף מבוסס IDE כדי להציג את קוד הביס של קובץ מחלקה. למשל, בואו נחקור את jclasslib צופה Bytecode תוסף זמין עבור IntelliJ IDEA.

7.1. הַתקָנָה

ראשית, נתקין את התוסף באמצעות תיבת הדו-שיח הגדרות / העדפות:

7.2. צפה ב- Bytecode של לְהִתְנַגֵד מעמד

לאחר מכן, אנו יכולים לבחור באפשרות "הצג Bytecode With Jclasslib" בתפריט View כדי להציג את קוד הקוד של הנבחר. לְהִתְנַגֵד מעמד:

לאחר מכן, ייפתח דו-שיח המציג את קוד הבסיס של ה- לְהִתְנַגֵד מעמד:

7.3. הצג פרטים

כמו כן, אנו יכולים לראות פרטים שונים של קוד הביצה כמו מאגר קבוע, שדות ושיטות באמצעות תיבת הדו-שיח תוסף Jclasslib:

באופן דומה, יש לנו את תוסף Visualizer של Bytecode כדי להציג את קוד הביס של קובץ מחלקה באמצעות ה- Eclipse IDE.

8. מסקנה

במדריך זה בדקנו דרכים להציג את קוד הביס של קובץ מחלקה ב- Java.

ראשית, בחנו את javap פיקוד יחד עם טיעוניו השונים. לאחר מכן עברנו כמה ספריות מניפולציה של bytecode המספקות את התכונות לצפייה ומניפולציה של קוד ה- bytecode.

אחרון בדקנו תוסף מבוסס IDE ג'קלאסליב המאפשר לנו להציג קוד byt ב- IntelliJ IDEA.

כרגיל, כל יישומי הקוד זמינים ב- GitHub.