Пример использования Java утилиты javap

от автора

JDK поставляется с рядом полезных утилит, размещенных в каталоге инструментов bin. Для тех, кто хочет декомпилировать байт-код, особый интерес представляет Java утилита javap.

Утилита командной строки javap, также известный как дизассемблер файлов классов Java, выводит соответствующую информацию о любом скомпилированном классе Java, который его просят проверить. По умолчанию он просто выводит имена всех неприватных методов и переменных, объявленных в классе:

C:\_tools\java8\javap example\bin>javap com.mcnz.javap.example.CommandTutorial Compiled from "CommandTutorial.java" public class com.mcnz.javap.example.CommandTutorial extends java.util.ArrayList<java.lang.Object> { protected static java.lang.String foo; public java.lang.String bar; public com.mcnz.javap.example.CommandTutorial(); void doStuff(); public static void main(java.lang.String[]); public void useInnerType(); }

Дизассемблер файла класса javap

По общему признанию, приведенный выше неинтересный вывод генерируется утилитой javap для проверки байт-кода, сгенерированного при компиляции класса CommandTutorial ниже. Обратите внимание на то, что в классе есть множество переменных и методов с множеством модификаторов доступа. По умолчанию JDK утилита javap выводит информацию только о полях, не являющихся private, хотя флаг -private позволяет предоставить информацию о private элементах.

package com.mcnz.javap.example; import java.util.ArrayList;  public class CommandTutorial extends ArrayList<Object> {    private static final long serialVersionUID = 1L;   protected static String foo;   public String bar;    void doStuff() { }   private String doStringStuff() { return null; }    public static void main(String args[]) {     class InnerClass {       public String stringStuff() {return "";};     }   }    interface InnerType { public void singleMethod(); };    public void useInnerType() {     InnerType innerTypeImpl = () -> System.out.println("javap example!");   } }

Популярные параметры команды javap

Вывод утилиты javap по умолчанию не особенно интересен. Однако есть множество флагов, которые можно использовать для вывода значительно более интересной информации. Популярные параметры и флаги команды javap включают:

  • -l распечатает таблицы локальных переменных для класса

  • -s будет печатать внутренние типы сигнатуры класса

  • -sysinfo отобразит дату последнего обновления, хеш MD5, путь и информацию о размере класса

  • -verbose выводит обширную информацию о размере стека, количестве аргументов и локальных переменных для методов, а также большой объем информации о структуре класса.

  • -c заставляет утилиту javap распечатать инструкции байт-кода Java, эффективно дизассемблируя класс

У утилиты javap есть несколько опций.  Команда javap с ключом sysinfo показывает хэш и информацию о последнем обновлении.
У утилиты javap есть несколько опций.  Команда javap с ключом sysinfo показывает хэш и информацию о последнем обновлении.

Как использовать команду javap

Большинство пользователей утилиты javap заинтересованы в декомпиляции класса и просмотре дизассемблированного байт-кода. Вот как использовать утилиту javap для просмотра байт-кода инструкций:

  1. Убедитесь, что утилита javap находятся по пути в переменной PATH операционной системы.

  2. Убедитесь, что класс для проверки javap скомпилирован

  3. Введите команду javap с параметром -c вместе с именем класса

  4. Просмотрите байт-код инструкций декомпилированного класса

Декомпилированный Java байт-код

Вот результат декомпиляции вышеуказанного класса с помощью инструмента Java javap.

C:\_tools\java8\javap example\bin> javap -verbose com.mcnz.javap.example.CommandTutorial  Classfile /C:/_tools/java8/javap example/bin/com/mcnz/javap/example/CommandTutorial.class   Last modified Nov 25, 2021; size 1864 bytes   MD5 checksum f1239fdfb14b9d5874f157242d884ea7   Compiled from "CommandTutorial.java" public class com.mcnz.javap.example.CommandTutorial extends java.util.ArrayList<java.lang.Object>   minor version: 0   major version: 55   flags: (0x0021) ACC_PUBLIC, ACC_SUPER   this_class: #1                          // com/mcnz/javap/example/CommandTutorial   super_class: #3                         // java/util/ArrayList   interfaces: 0, fields: 3, methods: 6, attributes: 5 Constant pool:    #1 = Class              #2             // com/mcnz/javap/example/CommandTutorial    #2 = Utf8               com/mcnz/javap/example/CommandTutorial    #3 = Class              #4             // java/util/ArrayList    #4 = Utf8               java/util/ArrayList    #5 = Utf8               serialVersionUID    #6 = Utf8               J    #7 = Utf8               ConstantValue    #8 = Long               1l   #10 = Utf8               foo   #11 = Utf8               Ljava/lang/String;   #12 = Utf8               bar   #13 = Utf8               <init>   #14 = Utf8               ()V   #15 = Utf8               Code   #16 = Methodref          #3.#17         // java/util/ArrayList."<init>":()V   #17 = NameAndType        #13:#14        // "<init>":()V   #18 = Utf8               LineNumberTable   #19 = Utf8               LocalVariableTable   #20 = Utf8               this   #21 = Utf8               Lcom/mcnz/javap/example/CommandTutorial;   #22 = Utf8               doStuff   #23 = Utf8               doStringStuff   #24 = Utf8               ()Ljava/lang/String;   #25 = Utf8               main   #26 = Utf8               ([Ljava/lang/String;)V   #27 = Utf8               args   #28 = Utf8               [Ljava/lang/String;   #29 = Utf8               useInnerType   #30 = InvokeDynamic      #0:#31         // #0:singleMethod:()Lcom/mcnz/javap/example/CommandTutorial$InnerType;   #31 = NameAndType        #32:#33        // singleMethod:()Lcom/mcnz/javap/example/CommandTutorial$InnerType;   #32 = Utf8               singleMethod   #33 = Utf8               ()Lcom/mcnz/javap/example/CommandTutorial$InnerType;   #34 = Utf8               innerTypeImpl   #35 = Utf8               Lcom/mcnz/javap/example/CommandTutorial$InnerType;   #36 = Utf8               lambda$0   #37 = Fieldref           #38.#40        // java/lang/System.out:Ljava/io/PrintStream;   #38 = Class              #39            // java/lang/System   #39 = Utf8               java/lang/System   #40 = NameAndType        #41:#42        // out:Ljava/io/PrintStream;   #41 = Utf8               out   #42 = Utf8               Ljava/io/PrintStream;   #43 = String             #44            // javap example!   #44 = Utf8               javap example!   #45 = Methodref          #46.#48        // java/io/PrintStream.println:(Ljava/lang/String;)V   #46 = Class              #47            // java/io/PrintStream   #47 = Utf8               java/io/PrintStream   #48 = NameAndType        #49:#50        // println:(Ljava/lang/String;)V   #49 = Utf8               println   #50 = Utf8               (Ljava/lang/String;)V   #51 = Utf8               SourceFile   #52 = Utf8               CommandTutorial.java   #53 = Utf8               Signature   #54 = Utf8               Ljava/util/ArrayList<Ljava/lang/Object;>;   #55 = Utf8               BootstrapMethods   #56 = Methodref          #57.#59        // java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljav a/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;   #57 = Class              #58            // java/lang/invoke/LambdaMetafactory   #58 = Utf8               java/lang/invoke/LambdaMetafactory   #59 = NameAndType        #60:#61        // metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang /invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;   #60 = Utf8               metafactory   #61 = Utf8               (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lan g/invoke/MethodType;)Ljava/lang/invoke/CallSite;   #62 = MethodHandle       6:#56          // REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invok e/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;   #63 = MethodType         #14            //  ()V   #64 = Methodref          #1.#65         // com/mcnz/javap/example/CommandTutorial.lambda$0:()V   #65 = NameAndType        #36:#14        // lambda$0:()V   #66 = MethodHandle       6:#64          // REF_invokeStatic com/mcnz/javap/example/CommandTutorial.lambda$0:()V   #67 = MethodType         #14            //  ()V   #68 = Utf8               InnerClasses   #69 = Class              #70            // com/mcnz/javap/example/CommandTutorial$1InnerClass   #70 = Utf8               com/mcnz/javap/example/CommandTutorial$1InnerClass   #71 = Utf8               InnerClass   #72 = Class              #73            // com/mcnz/javap/example/CommandTutorial$InnerType   #73 = Utf8               com/mcnz/javap/example/CommandTutorial$InnerType   #74 = Utf8               InnerType   #75 = Class              #76            // java/lang/invoke/MethodHandles$Lookup   #76 = Utf8               java/lang/invoke/MethodHandles$Lookup   #77 = Class              #78            // java/lang/invoke/MethodHandles   #78 = Utf8               java/lang/invoke/MethodHandles   #79 = Utf8               Lookup   #80 = Utf8               NestMembers {   protected static java.lang.String foo;     descriptor: Ljava/lang/String;     flags: (0x000c) ACC_PROTECTED, ACC_STATIC    public java.lang.String bar;     descriptor: Ljava/lang/String;     flags: (0x0001) ACC_PUBLIC    public com.mcnz.javap.example.CommandTutorial();     descriptor: ()V     flags: (0x0001) ACC_PUBLIC     Code:       stack=1, locals=1, args_size=1          0: aload_0          1: invokespecial #16                 // Method java/util/ArrayList."<init>":()V          4: return       LineNumberTable:         line 5: 0       LocalVariableTable:         Start  Length  Slot  Name   Signature             0       5     0  this   Lcom/mcnz/javap/example/CommandTutorial;    void doStuff();     descriptor: ()V     flags: (0x0000)     Code:       stack=0, locals=1, args_size=1          0: return       LineNumberTable:         line 11: 0       LocalVariableTable:         Start  Length  Slot  Name   Signature             0       1     0  this   Lcom/mcnz/javap/example/CommandTutorial;    public static void main(java.lang.String[]);     descriptor: ([Ljava/lang/String;)V     flags: (0x0009) ACC_PUBLIC, ACC_STATIC     Code:       stack=0, locals=1, args_size=1          0: return       LineNumberTable:         line 19: 0       LocalVariableTable:         Start  Length  Slot  Name   Signature             0       1     0  args   [Ljava/lang/String;    public void useInnerType();     descriptor: ()V     flags: (0x0001) ACC_PUBLIC     Code:       stack=1, locals=2, args_size=1          0: invokedynamic #30,  0             // InvokeDynamic #0:singleMethod:()Lcom/mcnz/javap/example/CommandTutorial$InnerType;          5: astore_1          6: return       LineNumberTable:         line 26: 0         line 27: 6       LocalVariableTable:         Start  Length  Slot  Name   Signature             0       7     0  this   Lcom/mcnz/javap/example/CommandTutorial;             6       1     1 innerTypeImpl   Lcom/mcnz/javap/example/CommandTutorial$InnerType; } SourceFile: "CommandTutorial.java" Signature: #54                          // Ljava/util/ArrayList<Ljava/lang/Object;>; BootstrapMethods:   0: #62 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/Metho       stack=0, locals=1, args_size=1          0: return       LineNumberTable:         Start  Length  Slot  Name   Signature             0       1     0  args   [Ljava/lang/String;    public void useInnerType();     descriptor: ()V     flags: (0x0001) ACC_PUBLIC     Code:       stack=1, locals=2, args_size=1          0: invokedynamic #30,  0             // InvokeDynamic #0:singleMethod:()Lcom/mcnz/javap/example/CommandTutorial$InnerType;          5: astore_1          6: return       LineNumberTable:         line 26: 0         line 27: 6       LocalVariableTable:         Start  Length  Slot  Name   Signature             0       7     0  this   Lcom/mcnz/javap/example/CommandTutorial;             6       1     1 innerTypeImpl   Lcom/mcnz/javap/example/CommandTutorial$InnerType; } SourceFile: "CommandTutorial.java" Signature: #54                          // Ljava/util/ArrayList<Ljava/lang/Object;>; BootstrapMethods:   0: #62 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/Metho dType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;     Method arguments:       #63 ()V         line 19: 0       LocalVariableTable:         Start  Length  Slot  Name   Signature             0       1     0  args   [Ljava/lang/String;    public void useInnerType();     descriptor: ()V     flags: (0x0001) ACC_PUBLIC     Code:       stack=1, locals=2, args_size=1          0: invokedynamic #30,  0             // InvokeDynamic #0:singleMethod:()Lcom/mcnz/javap/example/CommandTutorial$InnerType;          5: astore_1          6: return       LineNumberTable:         line 26: 0         line 27: 6       LocalVariableTable:          Start  Length  Slot  Name   Signature             0       7     0  this   Lcom/mcnz/javap/example/CommandTutorial;             6       1     1 innerTypeImpl   Lcom/mcnz/javap/example/CommandTutorial$InnerType; } SourceFile: "CommandTutorial.java" Signature: #54                          // Ljava/util/ArrayList<Ljava/lang/Object;>; BootstrapMethods:   0: #62 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang /invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;     Method arguments:       #63 ()V       #66 REF_invokeStatic com/mcnz/javap/example/CommandTutorial.lambda$0:()V       #67 ()V InnerClasses:   #71= #69;                               // InnerClass=class com/mcnz/javap/example/CommandTutorial$1InnerClass   static #74= #72 of #1;                  // InnerType=class com/mcnz/javap/example/CommandTutorial$InnerType of class com/mcnz/javap/example /CommandTutorial   public static final #79= #75 of #77;    // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles NestMembers:   com/mcnz/javap/example/CommandTutorial$1InnerClass   com/mcnz/javap/example/CommandTutorial$InnerType  C:\_tools\java8\javap example\bin>javap -c com.mcnz.javap.example.CommandTutorial Compiled from "CommandTutorial.java" public class com.mcnz.javap.example.CommandTutorial extends java.util.ArrayList<java.lang.Object> {   protected static java.lang.String foo;    public java.lang.String bar;    public com.mcnz.javap.example.CommandTutorial();     Code:        0: aload_0        1: invokespecial #16                 // Method java/util/ArrayList."<init>":()V        4: return    void doStuff();     Code:        0: return    public static void main(java.lang.String[]);     Code:        0: return    public void useInnerType();     Code:        0: invokedynamic #30,  0             // InvokeDynamic #0:singleMethod:()Lcom/mcnz/javap/example/CommandTutorial$InnerType;        5: astore_1        6: return }

Результаты выполнения команды javap являются подробными и обширными. Для тех, кому интересно взглянуть на некоторые внутренние механизмы скомпилированного байт-кода Java, утилита javap — это правильная команда.


ссылка на оригинал статьи https://habr.com/ru/articles/592161/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *