javap定義 測試類 javap命令參數 javap -version javap -p javap -public javap -protected javap -l javap -package javap -v/-p -v javap -c 文章開頭的demo中最終的結果是什麼呢? 這個地方 ...
javap定義
javap是 Java class文件分解器,可以反編譯(即對javac編譯的文件進行反編譯),也可以查看java編譯器生成的位元組碼。用於分解class文件。
測試類
public class JavapTest {
private static final int _P_1 = 1;
public static final int _P_2 = 2;
public static void main(String[] args) {
int m = 0, n = 0;
for (int i = 0; i < 10; i++) {
m = m++;
n = ++n;
}
System.out.println("m = " + m);
System.out.println("n = " + n);
}
}
javap命令參數
C:\>javap -help
用法: javap <options> <classes>
其中, 可能的選項包括:
-help --help -? 輸出此用法消息
-version 版本信息
-v -verbose 輸出附加信息
-l 輸出行號和本地變數表
-public 僅顯示公共類和成員
-protected 顯示受保護的/公共類和成員
-package 顯示程式包/受保護的/公共類
和成員 (預設)
-p -private 顯示所有類和成員
-c 對代碼進行反彙編
-s 輸出內部類型簽名
-sysinfo 顯示正在處理的類的
系統信息 (路徑, 大小, 日期, MD5 散列)
-constants 顯示靜態最終常量
-classpath <path> 指定查找用戶類文件的位置
-bootclasspath <path> 覆蓋引導類文件的位置
javap -version
C:\>javap -version
1.7.0_71
顯示java版本
javap -p
C:\Users\user\Desktop>javap -p JavapTest.class
Compiled from "JavapTest.java"
public class com.method.handler.JavapTest {
private static final int _P_1;
public static final int _P_2;
public com.method.handler.JavapTest();
public static void main(java.lang.String[]);
private void say();
}
顯示類所有可訪問修飾符範圍》private的成員
javap -public
C:\Users\user\Desktop>javap -public JavapTest.class
Compiled from "JavapTest.java"
public class com.method.handler.JavapTest {
public static final int _P_2;
public com.method.handler.JavapTest();
public static void main(java.lang.String[]);
}
顯示類的public成員
javap -protected
C:\Users\user\Desktop>javap -protected JavapTest.class
Compiled from "JavapTest.java"
public class com.method.handler.JavapTest {
public static final int _P_2;
public com.method.handler.JavapTest();
public static void main(java.lang.String[]);
}
顯示類所有可訪問修飾符範圍》protected的成員
javap -l
C:\Users\user\Desktop>javap -p -l JavapTest.class
Compiled from "JavapTest.java"
public class com.method.handler.JavapTest {
private static final int _P_1;
public static final int _P_2;
public com.method.handler.JavapTest();
LineNumberTable:
line 6: 0
public static void main(java.lang.String[]);
LineNumberTable:
line 12: 0
line 13: 4
line 14: 12
line 15: 17
line 13: 22
line 17: 28
line 18: 53
line 19: 78
private void say();
LineNumberTable:
line 23: 0
line 24: 8
}
輸出行號和本地變數表?看的不是很明白
javap -package
C:\Users\user\Desktop>javap -package JavapTest.class
Compiled from "JavapTest.java"
public class com.method.handler.JavapTest {
public static final int _P_2;
public com.method.handler.JavapTest();
public static void main(java.lang.String[]);
}
與javap -public作用類似
javap -v/-p -v
C:\Users\user\Desktop>javap -p -v JavapTest.class
Classfile /C:/Users/frinder_liu/Desktop/JavapTest.class
Last modified 2016-4-27; size 911 bytes
MD5 checksum e903be7495f5c462d6459a792e063628
Compiled from "JavapTest.java"
public class com.method.handler.JavapTest
SourceFile: "JavapTest.java"
minor version: 0
major version: 51
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #13.#30 // java/lang/Object."<init>":()V
#2 = Fieldref #31.#32 // java/lang/System.out:Ljava/io/PrintStream;
#3 = Class #33 // java/lang/StringBuilder
#4 = Methodref #3.#30 // java/lang/StringBuilder."<init>":()V
#5 = String #34 // m =
#6 = Methodref #3.#35 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilde
r;
#7 = Methodref #3.#36 // java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
#8 = Methodref #3.#37 // java/lang/StringBuilder.toString:()Ljava/lang/String;
#9 = Methodref #38.#39 // java/io/PrintStream.println:(Ljava/lang/String;)V
#10 = String #40 // n =
#11 = String #41 // hello world...
#12 = Class #42 // com/method/handler/JavapTest
#13 = Class #43 // java/lang/Object
#14 = Utf8 _P_1
#15 = Utf8 I
#16 = Utf8 ConstantValue
#17 = Integer 1
#18 = Utf8 _P_2
#19 = Integer 2
#20 = Utf8 <init>
#21 = Utf8 ()V
#22 = Utf8 Code
#23 = Utf8 LineNumberTable
#24 = Utf8 main
#25 = Utf8 ([Ljava/lang/String;)V
#26 = Utf8 StackMapTable
#27 = Utf8 say
#28 = Utf8 SourceFile
#29 = Utf8 JavapTest.java
#30 = NameAndType #20:#21 // "<init>":()V
#31 = Class #44 // java/lang/System
#32 = NameAndType #45:#46 // out:Ljava/io/PrintStream;
#33 = Utf8 java/lang/StringBuilder
#34 = Utf8 m =
#35 = NameAndType #47:#48 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#36 = NameAndType #47:#49 // append:(I)Ljava/lang/StringBuilder;
#37 = NameAndType #50:#51 // toString:()Ljava/lang/String;
#38 = Class #52 // java/io/PrintStream
#39 = NameAndType #53:#54 // println:(Ljava/lang/String;)V
#40 = Utf8 n =
#41 = Utf8 hello world...
#42 = Utf8 com/method/handler/JavapTest
#43 = Utf8 java/lang/Object
#44 = Utf8 java/lang/System
#45 = Utf8 out
#46 = Utf8 Ljava/io/PrintStream;
#47 = Utf8 append
#48 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder;
#49 = Utf8 (I)Ljava/lang/StringBuilder;
#50 = Utf8 toString
#51 = Utf8 ()Ljava/lang/String;
#52 = Utf8 java/io/PrintStream
#53 = Utf8 println
#54 = Utf8 (Ljava/lang/String;)V
{
private static final int _P_1;
flags: ACC_PRIVATE, ACC_STATIC, ACC_FINAL
ConstantValue: int 1
public static final int _P_2;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
ConstantValue: int 2
public com.method.handler.JavapTest();
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 6: 0
public static void main(java.lang.String[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=4, args_size=1
0: iconst_0
1: istore_1
2: iconst_0
3: istore_2
4: iconst_0
5: istore_3
6: iload_3
7: bipush 10
9: if_icmpge 28
12: iload_1
13: iinc 1, 1
16: istore_1
17: iinc 2, 1
20: iload_2
21: istore_2
22: iinc 3, 1
25: goto 6
28: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
31: new #3 // class java/lang/StringBuilder
34: dup
35: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
38: ldc #5 // String m =
40: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/St
ringBuilder;
43: iload_1
44: invokevirtual #7 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
47: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
50: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
53: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
56: new #3 // class java/lang/StringBuilder
59: dup
60: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
63: ldc #10 // String n =
65: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/St
ringBuilder;
68: iload_2
69: invokevirtual #7 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
72: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
75: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
78: return
LineNumberTable:
line 12: 0
line 13: 4
line 14: 12
line 15: 17
line 13: 22
line 17: 28
line 18: 53
line 19: 78
StackMapTable: number_of_entries = 2
frame_type = 254 /* append */
offset_delta = 6
locals = [ int, int, int ]
frame_type = 250 /* chop */
offset_delta = 21
private void say();
flags: ACC_PRIVATE
Code:
stack=2, locals=1, args_size=1
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #11 // String hello world...
5: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 23: 0
line 24: 8
}
命令說明是:輸出附加信息
class文件的路徑、最後修改時間、文件大小等
類的全路徑、源(java)文件等
常量池
常量定義、值
構造方法
程式調用及執行邏輯(這個涉及的內容就比較多了)
總之,javap -v命令是很強大的一個命令!
javap -c
C:\Users\user\Desktop>javap -c JavapTest.class Compiled from "JavapTest.java" public class com.method.handler.JavapTest { public static final int _P_2; public com.method.handler.JavapTest(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: iconst_0 1: istore_1 2: iconst_0 3: istore_2 4: iconst_0 5: istore_3 6: iload_3 7: bipush 10 9: if_icmpge 28 12: iload_1 13: iinc 1, 1 16: istore_1 17: iinc 2, 1 20: iload_2 21: istore_2 22: iinc 3, 1 25: goto 6 28: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 31: new #3 // class java/lang/StringBuilder 34: dup 35: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V 38: ldc #5 // String m = 40: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/Stri ngBuilder; 43: iload_1 44: invokevirtual #7 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder; 47: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 50: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 53: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 56: new #3 // class java/lang/StringBuilder 59: dup 60: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V 63: ldc #10 // String n = 65: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/Stri ngBuilder; 68: iload_2 69: invokevirtual #7 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder; 72: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 75: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 78: return } 其實,javap -c 輸出內部javap -v中已經有了,我們詳細介紹下javap -c命令的輸出內容 0: iconst_0 前面0:表示執行的順序,iconst_0把值 0 放入棧頂,_0中的0代表壓棧的值,如:iconst_5,即把5壓入棧頂 1: istore_1 將棧頂的值放入變數1 中,_1代表變數的序列,本例中為:m,如:istore_2即為變數n賦值 6: iload_3 將變數3 即 i 的的值放入棧頂,與iconst不同的是,iload操作的值是已經定義好存在的值,iconst是定義時的壓棧操作
13: iinc 1, 1 將變數1 的值加1
文章開頭的demo中最終的結果是什麼呢?
m = 0
n = 10
為什麼呢?
我們來關註下這幾行:
12: iload_1 -- 將變數1 值放入棧項
13: iinc 1, 1 -- 將變數1 增加1 變為2,棧頂值仍然是1。其中第一個1 表示變數,第二個1 表示增量
16: istore_1 -- 將棧頂值賦值給變數1,變數1 仍然為1
17: iinc 2, 1 -- 將變數2 增加1 變為2,棧頂值仍然是1。其中第一個2 表示變數,第二個1 表示增量
20: iload_2 -- 將變數2 值放入棧頂
21: istore_2 -- 將棧頂值賦值給變數2,變數2 值為2
記住一個點:
int m = 0, n = 0;
m = m++; -- 會先將m值(即0)賦值給m後再++
n = ++n; -- n先++後再把值賦值給n
此時,m = 0, n = 1;
這個地方有點繞,需要多看幾次,理順邏輯與關係!
這裡可以參考下http://blog.csdn.net/junsure2012/article/details/7099222,講的很詳細也易懂!
javap -s/-p -s
C:\Users\user\Desktop>javap -p -s JavapTest.class
Compiled from "JavapTest.java"
public class com.method.handler.JavapTest {
private static final int _P_1;
Signature: I
public static final int _P_2;
Signature: I
public com.method.handler.JavapTest();
Signature: ()V
public static void main(java.lang.String[]);
Signature: ([Ljava/lang/String;)V
private void say();
Signature: ()V
}
輸出內部類型簽名
javap -sysinfo/-p -sysinfo
C:\Users\user\Desktop>javap -sysinfo JavapTest.class
Classfile /C:/Users/user/Desktop/JavapTest.class
Last modified 2016-4-27; size 911 bytes
MD5 checksum 3f6dfcf7121785760b234224c5d135fd
Compiled from "JavapTest.java"
public class com.method.handler.JavapTest {
public static final int _P_2;
public com.method.handler.JavapTest();
public static void main(java.lang.String[]);
}
顯示正在處理的類的
系統信息 (路徑, 大小, 日期, MD5 散列)
javap -constants/-p -constants
C:\Users\user\Desktop>javap -constants JavapTest.class
Compiled from "JavapTest.java"
public class com.method.handler.JavapTest {
public static final int _P_2 = 2;
public com.method.handler.JavapTest();
public static void main(java.lang.String[]);
}
顯示靜態最終常量
javap -classpath/-bootclasspath
先跳過