Zielony Smok - logo witryny

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).

Moduł 'animation01' w projekcie 'animations'
Rys. 1. Moduł ‘animation01’ w projekcie ‘animations’

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ń.