Narzędzie pozwala na deasemblację jednego lub więcej plików klas. Deasemblacja polega na przekształceniu binariów w tekst i pokazaniu kodu bajtowego. Komplet informacji o JVM i kodzie bajtowym możesz znaleźć w specyfikacjach Oracle. To co otrzymujemy na wyjściu (stdout) zależy od ustawionych opcji. Jeżeli żadna opcja nie jest ustawiona polecenie javap
drukuje pola oznaczone jako public
lub jako protected
oraz metody.
Składnia
javap [options] classes
[options]
[options] | Opis |
---|---|
-help albo --help albo -? |
Drukuje tekst pomocy dla javap |
-version |
Drukuje informację o wersji narzędzia |
-verbose albo -v |
Drukuje dodatkowe informacje o wybranych klasach |
-l |
Drukuje linię i tabelę zmiennych lokalnych |
-public |
Drukuje tylko publiczne klasy i członki (members) |
-protected |
Drukuje tylko chronione klasy i członki (members) |
-package | Drukuje klasy i członki pakietowe chronione i publiczne |
-private albo -p |
Drukuje wszystkie klasy i czlonki (members) |
-c |
Drukuje deasemblowany kod np. instrukcje, które tworzą kod bajtowy dla każdej metody w klasie |
-s |
Drukuje wewnętrzne sygnatury typów |
-sysinfo |
Pokazuje systemowe informacje o przetwarzanej klasie (ścieżka, wielkość, data, skrót MD5) |
-constants |
Pokazuje stałe oznaczone final constant |
--module module albo-m module |
Moduł zawierający klasy do deasemblacji |
--module-path path |
Ścieżka do modułów aplikacji |
--system jdk |
Ścieżka do modułów systemowych |
--class-path path albo-classpath path albo-cp path |
Ścieżka, której javap użyje do znalezienia plików klas użytkownika. Użycie tej opcji nadpisuje domyślną lub środowiskową ( CLASSPATH ) zmienną, jeśli jest ustawiona |
--bootclasspath path |
Nadpisuje położenie plików klas wstępnego ładowania (bootstrap) |
-Joption |
Specyfikuje opcje dla JVM (zostaną omówione przy omawianiu narzędzia java ). Na przykład:
javap -J-version javap -J-Djava.security.manager ↩ -J-Djava.security.policy=MyPolicy MyClassName |
classes
Specyfikuje jedną lub więcej klas oddzielonych spacjami do przetworzenia adnotacji.
Klasa może być znaleziona w ścieżce klas po:
- nazwie
path/to/MyClass.class
- URL-u
jar:file:///path/to/MyJar.jar!/mypkg/MyClass.class
- kwalifikowanej nazwie klasy
java.lang.Object
Narzędzie nie rozpoznaje wielowersyjnych (multirelease) plików JAR. Jeżeli użyjemy 'ścieżkowej’ formy polecenia zobaczymy podstawowe wejścia (base entry) we wszystkich plikach JAR, multiwersyjnych czy nie.
Aby deasemblować klasy z danej wersji należy użyć polecenia w formie URL.
Przykład (linia poleceń)
W Windows 10, JDK 12.0.2, IntelliJ IDEA mamy projekt 'animations’. W projekcie mamy jeden moduł 'animation01′ (Rys 5).
Tworzymy plik animation01.jar. Jak przygotowywać pliki JAR pokażę przy omawianiu narzędzia JDK jar
.
Pliki źródłowe + JAR możesz ściągnąć stąd: animation01
Plik JAR umieszczamy w folderze C:/assets/javap/
Z wiersza poleceń wydajemy polecenie:
C:\WINDOWS\system32>javap -p -c -s -constants jar:file:///C:/assets/javap/animation01.jar!/animation01/Card.class
Otrzymujemy:
Microsoft Windows [Version 10.0.18363.836] (c) 2019 Microsoft Corporation. Wszelkie prawa zastrzeżone. Active code page: 65001 C:\WINDOWS\system32>javap -p -c -s -constants jar:file:///C:/assets/javap/animation01.jar!/animation01/Card.class Compiled from "Card.java" public class animation01.Card extends javax.swing.JComponent { private static final long serialVersionUID = 5586338595500806338l; descriptor: J private static final int XSIZE = 182; descriptor: I private static final int YSIZE = 335; descriptor: I private final java.awt.image.BufferedImage bimage; descriptor: Ljava/awt/image/BufferedImage; public animation01.Card(java.lang.String); descriptor: (Ljava/lang/String;)V Code: 0: aload_0 1: invokespecial #1 // Method javax/swing/JComponent."<init>":()V 4: aload_0 5: aload_1 6: invokestatic #2 // Method fileToBimage3:(Ljava/lang/String;)Ljava/awt/image/BufferedImage; 9: putfield #3 // Field bimage:Ljava/awt/image/BufferedImage; 12: aload_0 13: aconst_null 14: invokevirtual #4 // Method setLayout:(Ljava/awt/LayoutManager;)V 17: aload_0 18: iconst_0 19: iconst_0 20: sipush 182 23: sipush 335 26: invokevirtual #6 // Method setBounds:(IIII)V 29: aload_0 30: new #7 // class java/awt/Dimension 33: dup 34: sipush 182 37: sipush 335 40: invokespecial #8 // Method java/awt/Dimension."<init>":(II)V 43: invokevirtual #9 // Method setPreferredSize:(Ljava/awt/Dimension;)V 46: return public void paintComponent(java.awt.Graphics); descriptor: (Ljava/awt/Graphics;)V Code: 0: aload_0 1: aload_1 2: invokespecial #10 // Method javax/swing/JComponent.paintComponent:(Ljava/awt/Graphics;)V 5: aload_1 6: checkcast #11 // class java/awt/Graphics2D 9: astore_2 10: aload_2 11: aload_0 12: getfield #3 // Field bimage:Ljava/awt/image/BufferedImage; 15: iconst_0 16: iconst_0 17: sipush 182 20: sipush 335 23: aload_0 24: invokevirtual #12 // Method java/awt/Graphics2D.drawImage:(Ljava/awt/Image;IIIILjava/awt/image/ImageObserver;)Z 27: pop 28: return private static java.awt.image.BufferedImage fileToBimage3(java.lang.String); descriptor: (Ljava/lang/String;)Ljava/awt/image/BufferedImage; Code: 0: aload_0 1: invokestatic #13 // Method loadImage:(Ljava/lang/String;)Ljava/awt/Image; 4: astore_1 5: invokestatic #14 // Method java/awt/GraphicsEnvironment.getLocalGraphicsEnvironment:()Ljava/awt/GraphicsEnvironment; 8: invokevirtual #15 // Method java/awt/GraphicsEnvironment.getDefaultScreenDevice:()Ljava/awt/GraphicsDevice; 11: invokevirtual #16 // Method java/awt/GraphicsDevice.getDefaultConfiguration:()Ljava/awt/GraphicsConfiguration; 14: astore_3 15: aload_3 16: aload_1 17: aconst_null 18: invokevirtual #17 // Method java/awt/Image.getWidth:(Ljava/awt/image/ImageObserver;)I 21: aload_1 22: aconst_null 23: invokevirtual #18 // Method java/awt/Image.getHeight:(Ljava/awt/image/ImageObserver;)I 26: invokevirtual #19 // Method java/awt/GraphicsConfiguration.createCompatibleImage:(II)Ljava/awt/image/BufferedImage; 29: astore_2 30: aload_2 31: invokevirtual #20 // Method java/awt/image/BufferedImage.getGraphics:()Ljava/awt/Graphics; 34: aload_1 35: iconst_0 36: iconst_0 37: aconst_null 38: invokevirtual #21 // Method java/awt/Graphics.drawImage:(Ljava/awt/Image;IILjava/awt/image/ImageObserver;)Z 41: pop 42: aload_2 43: areturn private static java.awt.Image loadImage(java.lang.String); descriptor: (Ljava/lang/String;)Ljava/awt/Image; Code: 0: invokestatic #22 // Method java/awt/Toolkit.getDefaultToolkit:()Ljava/awt/Toolkit; 3: aload_0 4: invokevirtual #23 // Method java/awt/Toolkit.getImage:(Ljava/lang/String;)Ljava/awt/Image; 7: astore_1 8: new #24 // class java/awt/MediaTracker 11: dup 12: new #25 // class javax/swing/JPanel 15: dup 16: invokespecial #26 // Method javax/swing/JPanel."<init>":()V 19: invokespecial #27 // Method java/awt/MediaTracker."<init>":(Ljava/awt/Component;)V 22: astore_2 23: aload_2 24: aload_1 25: iconst_0 26: invokevirtual #28 // Method java/awt/MediaTracker.addImage:(Ljava/awt/Image;I)V 29: aload_2 30: iconst_0 31: invokevirtual #29 // Method java/awt/MediaTracker.waitForID:(I)V 34: goto 43 37: astore_3 38: aload_3 39: invokevirtual #31 // Method java/lang/InterruptedException.getMessage:()Ljava/lang/String; 42: pop 43: aload_1 44: areturn Exception table: from to target type 29 34 37 Class java/lang/InterruptedException } C:\WINDOWS\system32>
Przykład (ToolProvider
)
Polecenie możemy wykonać z poziomu klasy Java (javap.TP_javap
)
package javap; import java.util.Optional; import java.util.function.Consumer; import java.util.spi.ToolProvider; public class TP_javap { public static void main(String[] args){ Optional<ToolProvider> javap = ToolProvider.findFirst("javap"); javap.ifPresent(new Consumer<ToolProvider>() { @Override public void accept(ToolProvider toolProvider) { toolProvider.run(System.out, System.err, "-p", "-c", "-s", "-constants", "jar:file:///C:/assets/javap/animation01.jar!/animation01/Card.class"); } }); } }
Wynik wykonania jest dokładnie identyczny jak w przykładzie użycia przy pomocy linii poleceń.
Przykład (ProcessBuilder
)
Polecenie możemy wykonać z poziomu klasy Java (javap.PB_javap
)
package javap; import java.io.BufferedReader; import java.io.IOException; public class PB_javap { public static void main(String[] args){ try { ProcessBuilder pb = new ProcessBuilder(); pb.command("javap", "-p", "-c", "-s", "-constants", "jar:file:///C:/assets/javap/animation01.jar!/animation01/Card.class"); Process p = pb.start(); BufferedReader r = p.inputReader(); String line; while ((line = r.readLine()) != null) { System.out.println(line); } int exitCode = p.waitFor(); System.out.println("\nExited with code : " + exitCode); r.close(); p.destroy(); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } }
Wynik wykonania jest dokładnie identyczny jak w przykładzie użycia przy pomocy linii poleceń.