Pregledajte bytecode klasne datoteke na Javi

1. Pregled

Analiza bytecode-a uobičajena je praksa među programerima Java iz mnogih razloga, poput pronalaženja problema s kodom, profiliranja koda i pretraživanja klasa s određenim bilješkama.

U ovom ćemo članku istražiti načine za prikaz bytecode-a datoteke klase u Javi.

2. Što je bytecode?

Bytecode je posredni prikaz Java programa, omogućavajući JVM-u da prevede program u upute za montažu na razini stroja.

Kada se Java program kompilira, bytecode se generira u obliku .razred datoteka. Ovaj .razred datoteka sadrži upute koje se ne mogu pokrenuti i oslanja se na JVM koji treba protumačiti.

3. Korištenje javap

Naredbeni redak Java dolazi s javap alat koji prikazuje informacije o poljima, konstruktorima i metodama datoteke klase.

Na temelju korištenih opcija, može rastaviti klasu i prikazati upute koje sadrže Java bajtkod.

3.1. javap

Iskoristimo javap naredba za prikaz bytecode-a najčešćeg Objekt razred:

$ javap java.lang.Object

Izlaz naredbe prikazat će minimalnu konstrukciju Objekt razred:

javna klasa java.lang.Object {javna java.lang.Object (); javni konačni izvorni java.lang.Class getClass (); javni izvorni int hashCode (); javna logička vrijednost jednako (java.lang.Object); zaštićeni izvorni klon java.lang.Object () baca java.lang.CloneNotSupportedException; javna java.lang.String toString (); javna konačna izvorna void notify (); javna konačna nativna void notifyAll (); javno konačno nativno void čekanje (dugo) baca java.lang.InterruptedException; javno konačno void wait (long, int) baca java.lang.InterruptedException; javno konačno void wait () baca java.lang.InterruptedException; zaštićena praznina finalize () baca java.lang.Throwable; statički {}; }

Prema zadanim postavkama, izlaz bajtkoda neće sadržavati polja / metode s privatnik modifikator pristupa.

3.2. javap-str

Da bismo pregledali sve razrede i članove, možemo koristiti -str argument:

javna klasa java.lang.Object {javna java.lang.Object (); privatni statički izvorni void registerNatives (); javni konačni izvorni java.lang.Class getClass (); javni izvorni int hashCode (); javna logička vrijednost jednako (java.lang.Object); zaštićeni izvorni klon java.lang.Object () baca java.lang.CloneNotSupportedException; // ...}

Ovdje možemo primijetiti a privatni metoda registerNatives je također prikazan u bytecodeu Objekt razred.

3.3. javap-v

Slično tome, možemo koristiti -v argument za prikaz detaljnih podataka poput veličine sloga i argumenata za metode Objekt razred:

Jar datoteke datoteke: datoteka: /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/rt.jar! /Java/lang/Object.class Posljednja izmjena 15. ožujka 2017 .; veličina 1497 bajtova MD5 kontrolna suma 5916745820b5eb3e5647da3b6cc6ef65 Sastavljeno iz "Object.java" javne klase java.lang.Object minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: # 1 = Class # 49 // java / lang / StringBuild / ... {public java.lang.Object (); deskriptor: () V zastavice: ACC_PUBLIC Šifra: stog = 0, lokalci = 1, args_size = 1 0: return LineNumberTable: redak 37: 0 javni konačni izvorni java.lang.Class getClass (); deskriptor: () Ljava / lang / Class; zastavice: ACC_PUBLIC, ACC_FINAL, ACC_NATIVE Potpis: # 26 // () Ljava / lang / Class; // ...} Izvorna datoteka: "Object.java"

3.4. javap-c

Također, javap naredba omogućuje rastavljanje cijele Java klase pomoću -c argument:

Sastavljeno iz javne klase "Object.java" java.lang.Object {public java.lang.Object (); Šifra: 0: vrati javnu logičku vrijednost jednako (java.lang.Object); Šifra: 0: aload_0 1: aload_1 2: if_acmpne 9 5: iconst_1 6: goto 10 9: iconst_0 10: ireturn zaštićen izvorni java.lang.Object klon () baca java.lang.CloneNotSupportedException; // ...}

Nadalje, javap naredba omogućuje nam provjeru informacija o sustavu, konstanti i potpisa internog tipa pomoću različitih argumenata.

Možemo navesti sve argumente podržane javap naredba pomoću -Pomozite argument.

Sad kad smo vidjeli rješenje Java naredbenog retka za pregled bajtkoda datoteke klase, ispitajmo nekoliko biblioteka za manipulaciju bajt kodom.

4. Korištenje ASM-a

ASM je popularan okvir za manipulaciju i analizu Java bajt koda koji je usmjeren na izvedbu.

4.1. Postaviti

Prvo, dodajmo najnovije asm i asm-util Maven ovisnosti o našim pom.xml:

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

4.2. Prikaži bajtkod

Zatim ćemo upotrijebiti ClassReader i TraceClassVisitor za prikaz bajtkoda datoteke Objekt razred:

isprobajte {ClassReader čitač = novi ClassReader ("java.lang.Object"); StringWriter sw = novi StringWriter (); TraceClassVisitor tcv = novi TraceClassVisitor (novi PrintWriter (System.out)); reader.accept (tcv, 0); } catch (IOException e) {e.printStackTrace (); }

Ovdje ćemo primijetiti da TraceClassVisitor objekt zahtijeva PrintWriter objekt za izdvajanje i proizvodnju bytecode-a:

// verzija klase 52.0 (52) // pristup zastavicama 0x21 javna klasa java / lang / Object {// sastavljeno iz: Object.java // pristup zastavicama 0x1 public () V L0 LINIJUM 37 L0 POVRATAK MAXSTACK = 0 MAXLOCALS = 1 / / pristup zastavicama 0x101 javni izvorni hashCode () I // pristup zastavicama 0x1 javni jednako (Ljava / lang / Object;) Z L0 LINIJUMBER 149 L0 ALOAD 0 ALOAD 1 IF_ACMPNE L1 ICONST_1 GOTO L2 L1 // ...}

5. Korištenje BCEL-a

Biblioteka Byte Code Engineering, popularno poznata kao Apache Commons BCEL, pruža prikladan način za stvaranje / upravljanje datotekama Java klase.

5.1. Ovisnost Mavena

Kao i obično, dodajmo najnovije bcel Mavenova ovisnost o našoj pom.xml:

 org.apache.bcel bcel 6.5.0 

5.2. Rastavite klasu i pogledajte bajt kod

Tada možemo koristiti Spremište klasa za generiranje JavaClass objekt:

isprobajte {JavaClass objectClazz = Repository.lookupClass ("java.lang.Object"); System.out.println (objectClazz.toString ()); } catch (ClassNotFoundException e) {e.printStackTrace (); }

Evo, koristili smo toString metoda na objektClazz objekt za prikaz bajt-koda u sažetom obliku:

javna klasa java.lang.Object naziv datoteke java.lang.Object kompajliran iz Object.java prevoditelja verzija 52.0 pristupne zastavice 33 konstantno spremište 78 unosa ACC_SUPER zastava true Atributi: SourceFile: Object.java 14 metoda: public void () private static native void registerNatives () javni konačni izvorni Class getClass () [Potpis: () Ljava / lang / Class;] public native int hashCode () javni boolean jednako (Object arg1) zaštićeni izvorni clone objekt () baca iznimke: java.lang .CloneNotSupportedException javni niz toString () javna konačna nativna void notify () // ...

Nadalje, JavaClass klasa pruža metode poput getConstantPool, getFields, i getMethods za pregled detalja rastavljene klase.

assertEquals (objectClazz.getFileName (), "java.lang.Object"); assertEquals (objectClazz.getMethods (). length, 14); assertTrue (objectClazz.toString (). sadrži ("javna klasa java.lang.Object")); 

Slično tome, postaviti * dostupne su metode za manipulaciju bajt kodom.

6. Korištenje Javassista

Također, možemo koristiti Javassist (Asistent za programiranje Java) knjižnica koja pruža API-je na visokoj razini za prikaz / manipulaciju Java bajt kodom.

6.1. Ovisnost Mavena

Prvo ćemo dodati najnovije javassist Mavenova ovisnost o našoj pom.xml:

 org.javassist javassist 3.27.0-GA 

6.2. Generirati ClassFile

Tada možemo koristiti ClassPool i ClassFile klase za generiranje Java klase:

isprobajte {ClassPool cp = ClassPool.getDefault (); ClassFile cf = cp.get ("java.lang.Object"). GetClassFile (); cf.write (novi DataOutputStream (novi FileOutputStream ("Object.class"))); } catch (NotFoundException e) {e.printStackTrace (); }

Evo, koristili smo pisati metoda koja nam omogućuje pisanje datoteke klase pomoću DataOutputStream objekt:

// Sastavljeno iz Object.java (verzija 1.8: 52.0, super bit) javne klase java.lang.Object {// Deskriptor metode # 19 () V // Stog: 0, Lokalno stanovništvo: 1 javni objekt (); 0 povratnih brojeva redaka: [pc: 0, line: 37] // Deskriptor metode # 19 () V privatni statički izvorni void registerNatives (); // Opisnik metode # 24 () Ljava / lang / Class; // Potpis: () Ljava / lang / Class; javni konačni izvorni java.lang.Class getClass (); // Opisnik metode # 28 () Javni izvorni int hashCode (); // ...

Također, objekt ClassFile klasa omogućuje pristup konstantnom spremištu, poljima i metodama:

assertEquals (usp. getName (), "java.lang.Object"); assertEquals (usp. getMethods (). size (), 14);

7. Jclasslib

Uz to, možemo koristiti dodatak zasnovan na IDE-u za prikaz bajt-koda datoteke klase. Na primjer, istražimo jclasslib Preglednik bajtkoda dodatak dostupan za IntelliJ IDEA.

7.1. Montaža

Prvo ćemo instalirati dodatak pomoću dijaloškog okvira Postavke / Postavke:

7.2. Pogledajte bajtkod datoteke Objekt Razred

Zatim, možemo odabrati opciju "Prikaži bajt kod s Jclasslib" u izborniku Pogled za prikaz bajt koda odabranog Objekt razred:

Dalje, otvorit će se dijaloški okvir za prikaz bajtkoda datoteke Objekt razred:

7.3. Pregledavati pojedinosti

Također, možemo vidjeti razne detalje bajt-koda poput konstantnog spremišta, polja i metoda pomoću dijaloškog okvira dodatka Jclasslib:

Slično tome, imamo i Dodatak za vizualizator bytecode-a za prikaz bytecode-a datoteke klase pomoću Eclipse IDE-a.

8. Zaključak

U ovom smo tutorijalu istražili načine za prikaz bajtkoda datoteke klase u Javi.

Prvo smo ispitali javap naredba zajedno s raznim argumentima. Zatim smo prošli kroz nekoliko biblioteka za manipulaciju bajt kodom koje pružaju značajke za prikaz i manipulaciju bajt kodom.

Na kraju smo pogledali dodatak zasnovan na IDE-u Jclasslib koji nam omogućuje prikaz bajt koda u IntelliJ IDEA.

Kao i obično, sve implementacije koda dostupne su na GitHubu.