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
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:
- Make sure the javap tools is on the PATH of the operating system
- Make sure the class to be inspected by javap is compiled
- Issue the javap command with the -c option along with the name of the class
- 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.