Tekintse meg az osztályfájl Bytecode-ját a Java-ban

1. Áttekintés

A bytecode elemzés sok okból elterjedt gyakorlat a Java-fejlesztők körében, például a kóddal kapcsolatos problémák keresése, a kódprofilozás és az osztályok keresése speciális kommentárokkal.

Ebben a cikkben azt vizsgáljuk, hogy miként tekinthető meg az osztályfájl bájtkódja Java-ban.

2. Mi a Bytecode?

A Bytecode a Java program közbenső ábrázolása, amely lehetővé teszi a JVM számára, hogy a programot gépi szintű összeszerelési utasításokká fordítsa.

Amikor Java programot fordítanak, a bytecode generálódik a formájában .osztály fájl. Ez .osztály fájl nem futtatható utasításokat tartalmaz, és egy értelmezendő JVM-re támaszkodik.

3. Használata javap

A Java parancssor a javap eszköz, amely információkat jelenít meg egy osztályfájl mezőiről, szerkesztőiről és módszereiről.

A felhasznált opciók alapján szétszerelhet egy osztályt, és megjelenítheti a Java byte-kódot tartalmazó utasításokat.

3.1. javap

Használjuk a javap parancs a leggyakoribb bájtkódjának megtekintéséhez Tárgy osztály:

$ javap java.lang.Object

A parancs kimenete megmutatja a Tárgy osztály:

java.lang.Object {public java.lang.Object () osztály; nyilvános végleges natív java.lang.Class getClass (); public native int hashCode (); nyilvános logikai egyenlő (java.lang.Object); védett natív java.lang.Object clone () dobja java.lang.CloneNotSupportedException; nyilvános java.lang.String toString (); nyilvános végleges natív érvénytelen értesítés (); nyilvános végleges natív érvénytelen értesítésAll (); public final native void wait (long) dobja a java.lang.InterruptedException; public final void wait (long, int) dobja a java.lang.InterruptedException; public final void wait () dobja a java.lang.InterruptedException; protected void finalize () dobja a java.lang.Trowble-t; statikus {}; }

Alapértelmezés szerint a bytecode kimenet nem tartalmaz mezőket / metódusokat a egy közlegény hozzáférés módosító.

3.2. javap-p

Az összes osztály és tag megtekintéséhez használhatjuk a -p érv:

java.lang.Object {public java.lang.Object () osztály; privát statikus natív űrregiszterNatívok (); nyilvános végleges natív java.lang.Class getClass (); public native int hashCode (); nyilvános logikai egyenlő (java.lang.Object); védett natív java.lang.Object clone () dobja java.lang.CloneNotSupportedException; // ...}

Itt megfigyelhetjük a magán módszer registerNatives a bájtkódjában is látható Tárgy osztály.

3.3. javap-v

Hasonlóképpen használhatjuk a -v argumentum a részletes információk, például a verem méretének és a Tárgy osztály:

Osztályfájl jar: fájl: /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/rt.jar! /Java/lang/Object.class Utolsó módosítás: 2017. március 15 .; 1497 byte MD5 ellenőrző összeg 5916745820b5eb3e5647da3b6cc6ef65 Összeállítva az "Object.java" nyilvános osztály java.lang.Object minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: # 1 = Class # 49 // java / lang / StringB / ... {public java.lang.Object (); leíró: () V zászlók: ACC_PUBLIC Kód: verem = 0, helyiek = 1, args_size = 1 0: return LineNumberTable: 37. sor: 0 nyilvános végleges natív java.lang.Class getClass (); leíró: () Ljava / lang / Class; zászlók: ACC_PUBLIC, ACC_FINAL, ACC_NATIVE Aláírás: # 26 // () Ljava / lang / Class; // ...} SourceFile: "Object.java"

3.4. javap-c

Továbbá a javap parancs lehetővé teszi a teljes Java osztály szétszerelését a -c érv:

Összeállítva az "Object.java" nyilvános osztályból java.lang.Object {public java.lang.Object (); Kód: 0: return public boolean egyenlő (java.lang.Object); Kód: 0: aload_0 1: aload_1 2: if_acmpne 9 5: iconst_1 6: goto 10 9: iconst_0 10: védett natív java.lang.Object klón () dobja a java.lang.CloneNotSupportedException; // ...}

Továbbá a javap parancs lehetővé teszi számunkra, hogy különféle argumentumok segítségével ellenőrizzük a rendszerinformációkat, az állandókat és a belső típusú aláírásokat.

Felsorolhatunk minden argumentumot, amelyet a javap parancsot a -Segítség érv.

Most, hogy láttunk egy Java parancssori megoldást egy osztályfájl bájtkódjának megtekintésére, vizsgáljunk meg néhány bájtkód-manipulációs könyvtárat.

4. Az ASM használata

Az ASM egy népszerű teljesítményorientált, alacsony szintű Java bytecode manipulációs és elemzési keretrendszer.

4.1. Beállít

Először tegyük hozzá a legfrissebbet asm és asm-util Maven függőségek a mi pom.xml:

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

4.2. A Bytecode megtekintése

Akkor használjuk a ClassReader és TraceClassVisitor hogy megtekinthesse a Tárgy osztály:

próbáld ki a {ClassReader olvasót = új ClassReader ("java.lang.Object"); StringWriter sw = új StringWriter (); TraceClassVisitor tcv = új TraceClassVisitor (új PrintWriter (System.out)); olvasó.elfogad (tcv, 0); } catch (IOException e) {e.printStackTrace (); }

Itt megjegyezzük, hogy a TraceClassVisitor objektum megköveteli a PrintWriter objektum a bájtkód kinyerésére és előállítására:

// class version 52.0 (52) // access flags 0x21 public class java / lang / Object {// fordítva: Object.java // hozzáférési flagek 0x1 public () V L0 LINENUMBER 37 L0 RETURN MAXSTACK = 0 MAXLOCALS = 1 / / access flags 0x101 public native hashCode () I // access flags 0x1 public egyenlő (Ljava / lang / Object;) Z L0 LINENUMBER 149 L0 ALOAD 0 ALOAD 1 IF_ACMPNE L1 ICONST_1 GOTO L2 L1 // ...}

5. A BCEL használata

A Byte Code Engineering Library, közismertebb nevén Apache Commons BCEL, kényelmes módot kínál a Java osztályú fájlok létrehozására / kezelésére.

5.1. Maven-függőség

Szokás szerint tegyük hozzá a legfrissebbet bcel Maven függőség a mi pom.xml:

 org.apache.bcel bcel 6.5.0 

5.2. Szedje szét az osztályt és nézze meg a Bytecode-ot

Ezután használhatjuk a Adattár osztály a JavaClass tárgy:

próbáld ki a {JavaClass objectClazz = Repository.lookupClass ("java.lang.Object") parancsot; System.out.println (objectClazz.toString ()); } catch (ClassNotFoundException e) {e.printStackTrace (); }

Itt használtuk a Sztring módszer a objectClazz objektum, hogy tömör formátumban lássa a bájtkódot:

java.lang.objekt fájlnév java.lang.Object az Object.java fordító 52.0-s verziójából összeállítva hozzáférési jelzők 33 állandó készlet 78 bejegyzés ACC_SUPER flag true Attribútum (ok): SourceFile: Object.java 14 módszer: public void () private static native void registerNatives () public final native class getClass () [Signature: () Ljava / lang / Class;] public native int hashCode () public boolean egyenlő (Object arg1) védett natív Object klón () dobja a kivételeket: java.lang .CloneNotSupportedException public String toString () nyilvános végleges natív érvénytelen értesítés () // ...

Továbbá a JavaClass osztály olyan módszereket nyújt, mint getConstantPool, getFields, és getMethods a szétszedett osztály részleteinek megtekintéséhez.

assertEquals (objectClazz.getFileName (), "java.lang.Object"); assertEquals (objectClazz.getMethods (). hossz, 14); assertTrue (objectClazz.toString (). tartalmazza ("java.lang.Object nyilvános osztály")); 

Hasonlóképpen, készlet* módszerek állnak rendelkezésre a bytecode manipulációra.

6. Javassist használata

Használhatjuk a Javassist (Java programozási asszisztens) könyvtár, amely magas szintű API-kat biztosít a Java bytecode megtekintésére / kezelésére.

6.1. Maven-függőség

Először hozzáadjuk a legfrissebbet javassist Maven függőség a mi pom.xml:

 org.javassist javassist 3.27.0-GA 

6.2. generál ClassFile

Ezután használhatjuk a ClassPool és ClassFile osztályok Java osztály létrehozásához:

próbáld ki a {ClassPool cp = ClassPool.getDefault (); ClassFile cf = cp.get ("java.lang.Object"). GetClassFile (); cf.write (új DataOutputStream (új FileOutputStream ("Object.class"))); } catch (NotFoundException e) {e.printStackTrace (); }

Itt használtuk a ír metódus, amely lehetővé teszi számunkra, hogy az osztályfájlt a DataOutputStream tárgy:

// Az Object.java (1.8 verzió: 52.0, szuper bit) Public class java.lang.Object {// Metódusleíró # 19 () V // Verem: 0, Helyiek: 1 nyilvános objektum (); 0 return Sorszámok: [pc: 0, sor: 37] // Metódleíró # 19 () V privát statikus natív void registerNatives (); // Metódleíró # 24 () Ljava / lang / Class; // Aláírás: () Ljava / lang / Class; nyilvános végleges natív java.lang.Class getClass (); // Módszerleíró # 28 () I public native int hashCode (); // ...

Továbbá a ClassFile osztály hozzáférést biztosít az állandó készlethez, mezőkhöz és módszerekhez:

assertEquals (cf.getName (), "java.lang.Object"); assertEquals (vö .getMethods (). méret (), 14);

7. Jclasslib

Ezenkívül egy IDE alapú beépülő modult is használhatunk egy osztályfájl byte-kódjának megtekintésére. Fedezzük fel például a jclasslib Bytecode néző bővítmény elérhető az IntelliJ IDEA számára.

7.1. Telepítés

Először telepítjük a beépülő modult a Beállítások / Beállítások párbeszédpanelen:

7.2. Tekintse meg a Tárgy Osztály

Ezután kiválaszthatjuk a Nézet menü „Bitecode megjelenítése Jclasslib-lel” opciót a kiválasztott bájtkódjának megtekintéséhez. Tárgy osztály:

Ezután megnyílik egy párbeszédpanel, amely megmutatja a Tárgy osztály:

7.3. Részletek megtekintése

Ezenkívül a Jclasslib plugin párbeszédpanel segítségével láthatjuk a bájtkód különböző részleteit, például az állandó készletet, a mezőket és a módszereket:

Hasonlóképpen megvan a Bytecode Visualizer beépülő modul osztályfájl bájtkódjának megtekintéséhez az Eclipse IDE használatával.

8. Következtetés

Ebben az oktatóanyagban megvizsgáltuk, hogyan lehet egy osztályfájlt bájtkódot megtekinteni Java-ban.

Először megvizsgáltuk a javap parancsot a különböző érveivel együtt. Ezután átmentünk néhány bytecode manipulációs könyvtáron, amelyek biztosítják a bytecode megtekintésének és kezelésének lehetőségeit.

Utoljára egy IDE alapú plugint vizsgáltunk Jclasslib ez lehetővé teszi számunkra a bytecode megtekintését az IntelliJ IDEA-ban.

Szokás szerint az összes kód implementáció elérhető a GitHubon.