How to use Java's javap tool by example

Java’s javap tool example

When you install Java, the JDK comes with a number of helpful utilities packed within the toolkit’s bin directory. For those who wish to decompile bytecode, the Java’s javap command will be of special interest.

Also known as the Java class file disassembler, the command-line javap tool will output pertinent information about any compiled Java class it is asked to inspect. By default, it simply spits out the names of all of the non-private methods and variables declared within a class:

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();
}

The javap class file disassembler

The admittedly unexciting output above is generated by having the javap tool inspect the bytecode generated by the compilation the CommandTutorial class below. Note how the class has a variety of variables and methods with a variety of access modifiers. By default, the JDK’s javap tool will only output information about non-private fields, although the -private flag will provide information about private items as well.

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!");
  }
}

Popular javap command options

The default output of the javap tool isn’t particularly exciting. However, there are a variety of flags that can be used to output a decidedly more interesting information. Popular javap command options and flags include:

  • -l will print out the local variable tables for the class
  • -s will print internal type signatures of the class
  • -sysinfo will display the last update date, MD5 hash, path and size information about the class
  • -verbose prints out extensive information about stack size, the number of arguments and locals for methods, along with a great deal of information about how the class is structure
  • -c gets the javap tool to print out Java bytecode instructions, effectively disassembling the class
javap command tool example

The javap tool has a number of options. The javap command with the sysinfo switch shows hash and last update information.

How to use the javap command

Most users of the javap tool are interested in decompiling a class and viewing the disassembled bytecode. Here’s how to use the javap tool to view bytecode instructions:

  1. Make sure the javap tools is on the PATH of the operating system
  2. Make sure the class to be inspected by javap is compiled
  3. Issue the javap command with the -c option along with the name of the class
  4. View the bytecode instructions of the decompiled class

Decompiled Java bytecode

Here is the result of decompiling the above class with Java’s javap tool.

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 command example

The results of running the javap command are both verbose and extensive. But for those who are interested in looking at some of the inner workings of compiled bytecode in a Java installation, the javap utility is the right command to use.