Oracle官方說明:html
javap 將一個或多個類文件進行分解。 使用簡要說明 javap [options] classfile... options 命令行選項,詳細查看後面的Options介紹 classfile 一個或多個Class文件(多個使用空格分離),可使用文件路徑或者classPath下的文件或者輸入URL Description javap命令分解卸一個或多個類文件。輸出取決於所使用的選項。當沒有使用任何選項,那麼javap命令打印方案爲protected和公共字段和方法。javap命令將輸出打印到控制檯。 Options -help --help -? 打印幫助信息 -version 打印版本信息 -l 打印行內變量以及局部變量 -public 顯示public訪問修飾的內容 -protected 顯示protected、public訪問修飾的內容 -private -p 顯示全部的內容 -Joption 將指定的選項傳遞給JVM。例如: javap -J-version javap -J-Djava.security.manager -J-Djava.security.policy=MyPolicy MyClassName For more information about JVM options, see the java command documentation. -s 打印內部類簽名 -sysinfo 顯示系統信息(路徑、大小、日期、MD5哈希)的類處理。 -constants 顯示靜態常量 -c 爲每一個類中的方法打印反彙編代碼,例如,Java字節碼指令組成,。 -verbose 打印堆棧大小,局部變量的數目和方法的參數。 Prints stack size, number of locals and arguments for methods. -classpath path 指定javap命令使用的路徑查找類。覆蓋默認的或者當它被設置CLASSPATH環境變量。 Specifies the path the javap command uses to look up classes. Overrides the default or the CLASSPATH environment variable when it is set. -bootclasspath path 指定的路徑加載引導類。默認狀況下,引導類類,實現核心Java平臺位於jre / lib / rt。jar和其餘幾個jar文件。 Specifies the path from which to load bootstrap classes. By default, the bootstrap classes are the classes that implement the core Java platform located in jre/lib/rt.jar and several other JAR files. -extdir dirs 增長一些擴展路徑用以獲取類庫 Overrides the location at which installed extensions are searched for. The default location for extensions is the value of java.ext.dirs.
###咱們來看看String、StringBuffer、StringBuilder的不一樣 ####測試類java
public class Test { public static void main(String[] args) { long start = System.currentTimeMillis(); for (int i = 0; i < 100000; i++) { //咱們通常拼接字符的時候都不會拼接太屢次100次其實就算比較多了 contactStringWithLoop(100); } System.out.println(System.currentTimeMillis() - start); //916毫秒 start = System.currentTimeMillis(); for (int i = 0; i < 100000; i++) { //咱們通常拼接字符的時候都不會拼接太屢次100次其實就算比較多了 contactStringWithStringBuilder(100); } System.out.println(System.currentTimeMillis() - start); //244毫秒 start = System.currentTimeMillis(); for (int i = 0; i < 100000; i++) { //咱們通常拼接字符的時候都不會拼接太屢次100次其實就算比較多了 contactStringWithStringBuffer(100); } System.out.println(System.currentTimeMillis() - start); //620毫秒 } /** * 直接拼接字符串 * * @return */ public static String contactString() { String string = "直接" + "對字符串" + "進行" + "屢次的拼接" + "看看最後編譯" + "的字節碼" + "會是神馬" + "樣子" + "的"; return string; } /** * 與上面的方法其實一致,只是在拼接中引入了一個多個變量 * * @param str * @return */ public static String contactStringWithParam(String str, String str2, String str3) { String string = "直接" + str3 + "進行" + "屢次的拼接" + "看看最後編譯" + str + "會是神馬" + str2 + "的"; return string; } /** * 經過循環來拼接字符串 * * @param loopCount 循環的次數 * @return */ public static String contactStringWithLoop(int loopCount) { String string = ""; for (int i = 0; i < loopCount; i++) { string += i; } return string; } /** * 使用StringBuffer循環拼接字符串 * * @param loopCount * @return */ public static String contactStringWithStringBuffer(int loopCount) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < loopCount; i++) { sb.append(i); } return sb.toString(); } /** * 使用StringBuilder循環拼接字符串 * * @param loopCount * @return */ public static String contactStringWithStringBuilder(int loopCount) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < loopCount; i++) { sb.append(i); } return sb.toString(); } }
####使用javap -c Test 來得到字節碼信息shell
Compiled from "Test.java" public class Test { public Test(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: invokestatic #2 // Method java/lang/System.currentTimeMillis:()J 3: lstore_1 4: iconst_0 5: istore_3 6: iload_3 7: ldc #3 // int 100000 9: if_icmpge 24 12: bipush 100 14: invokestatic #4 // Method contactStringWithLoop:(I)Ljava/lang/String; 17: pop 18: iinc 3, 1 21: goto 6 24: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream; 27: invokestatic #2 // Method java/lang/System.currentTimeMillis:()J 30: lload_1 31: lsub 32: invokevirtual #6 // Method java/io/PrintStream.println:(J)V 35: invokestatic #2 // Method java/lang/System.currentTimeMillis:()J 38: lstore_1 39: iconst_0 40: istore_3 41: iload_3 42: ldc #3 // int 100000 44: if_icmpge 59 47: bipush 100 49: invokestatic #7 // Method contactStringWithStringBuilder:(I)Ljava/lang/String; 52: pop 53: iinc 3, 1 56: goto 41 59: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream; 62: invokestatic #2 // Method java/lang/System.currentTimeMillis:()J 65: lload_1 66: lsub 67: invokevirtual #6 // Method java/io/PrintStream.println:(J)V 70: invokestatic #2 // Method java/lang/System.currentTimeMillis:()J 73: lstore_1 74: iconst_0 75: istore_3 76: iload_3 77: ldc #3 // int 100000 79: if_icmpge 94 82: bipush 100 84: invokestatic #8 // Method contactStringWithStringBuffer:(I)Ljava/lang/String; 87: pop 88: iinc 3, 1 91: goto 76 94: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream; 97: invokestatic #2 // Method java/lang/System.currentTimeMillis:()J 100: lload_1 101: lsub 102: invokevirtual #6 // Method java/io/PrintStream.println:(J)V 105: return public static java.lang.String contactString(); Code: 0: ldc #9 // String 直接對字符串進行屢次的拼接看看最後編譯的字節碼會是神馬樣子的 2: astore_0 3: aload_0 4: areturn public static java.lang.String contactStringWithParam(java.lang.String, java.lang.String, java.lang.String); Code: 0: new #10 // class java/lang/StringBuilder 3: dup 4: invokespecial #11 // Method java/lang/StringBuilder."<init>":()V 7: ldc #12 // String 直接 9: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 12: aload_2 13: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 16: ldc #14 // String 進行 18: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 21: ldc #15 // String 屢次的拼接 23: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 26: ldc #16 // String 看看最後編譯 28: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 31: aload_0 32: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 35: ldc #17 // String 會是神馬 37: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 40: aload_1 41: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 44: ldc #18 // String 的 46: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 49: invokevirtual #19 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 52: astore_3 53: aload_3 54: areturn public static java.lang.String contactStringWithLoop(int); Code: 0: ldc #20 // String 2: astore_1 3: iconst_0 4: istore_2 5: iload_2 6: iload_0 7: if_icmpge 35 10: new #10 // class java/lang/StringBuilder 13: dup 14: invokespecial #11 // Method java/lang/StringBuilder."<init>":()V 17: aload_1 18: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 21: iload_2 22: invokevirtual #21 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder; 25: invokevirtual #19 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 28: astore_1 29: iinc 2, 1 32: goto 5 35: aload_1 36: areturn public static java.lang.String contactStringWithStringBuffer(int); Code: 0: new #22 // class java/lang/StringBuffer 3: dup 4: invokespecial #23 // Method java/lang/StringBuffer."<init>":()V 7: astore_1 8: iconst_0 9: istore_2 10: iload_2 11: iload_0 12: if_icmpge 27 15: aload_1 16: iload_2 17: invokevirtual #24 // Method java/lang/StringBuffer.append:(I)Ljava/lang/StringBuffer; 20: pop 21: iinc 2, 1 24: goto 10 27: aload_1 28: invokevirtual #25 // Method java/lang/StringBuffer.toString:()Ljava/lang/String; 31: areturn public static java.lang.String contactStringWithStringBuilder(int); Code: 0: new #10 // class java/lang/StringBuilder 3: dup 4: invokespecial #11 // Method java/lang/StringBuilder."<init>":()V 7: astore_1 8: iconst_0 9: istore_2 10: iload_2 11: iload_0 12: if_icmpge 27 15: aload_1 16: iload_2 17: invokevirtual #21 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder; 20: pop 21: iinc 2, 1 24: goto 10 27: aload_1 28: invokevirtual #19 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 31: areturn }
###咱們來分一下分解出的字節碼: #####contactString方法[在javac結果的64行]bootstrap
public static java.lang.String contactString(); Code: 0: ldc #9 // String 直接對字符串進行屢次的拼接看看最後編譯的字節碼會是神馬樣子的 2: astore_0 3: aload_0 4: areturn
從 0: ldc #9 // String 直接對字符串進行屢次的拼接看看最後編譯的字節碼會是神馬樣子的
這裏能夠看出,編譯器直接將編譯結果進行了轉換,沒有使用+而直接使用了拼接後的字符串(由於不包含變量的拼接,因此能夠預想到最終結果) 結論:對java中字符串直接拼接時能夠直接使用+的方式來拼接。 #####contactStringWithParam[在javac結果的71行]windows
public static java.lang.String contactStringWithParam(java.lang.String, java.lang.String, java.lang.String); Code: 0: new #10 // class java/lang/StringBuilder 3: dup 4: invokespecial #11 // Method java/lang/StringBuilder."<init>":()V 7: ldc #12 // String 直接 9: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 12: aload_2 13: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 16: ldc #14 // String 進行 18: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 21: ldc #15 // String 屢次的拼接 23: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 26: ldc #16 // String 看看最後編譯 28: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 31: aload_0 32: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 35: ldc #17 // String 會是神馬 37: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 40: aload_1 41: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 44: ldc #18 // String 的 46: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 49: invokevirtual #19 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 52: astore_3 53: aload_3 54: areturn
0: new #10 // class java/lang/StringBuilder
這句話是對應聲明瞭一個StringBuilder,而後每次拼接實際使用的是StringBuilder的append方法。 結論:在針對這種沒有循環可是有變變量拼接的字符串時,使用StringBuilder與使用String + 的方式沒有區別,可是String + 的方式更加省時省力,並且相對清晰。 #####contactStringWithLoop[在javac結果的99行]安全
public static java.lang.String contactStringWithLoop(int); Code: 0: ldc #20 // String 2: astore_1 3: iconst_0 4: istore_2 5: iload_2 6: iload_0 7: if_icmpge 35 10: new #10 // class java/lang/StringBuilder 13: dup 14: invokespecial #11 // Method java/lang/StringBuilder."<init>":()V 17: aload_1 18: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 21: iload_2 22: invokevirtual #21 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder; 25: invokevirtual #19 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 28: astore_1 29: iinc 2, 1 32: goto 5 35: aload_1 36: areturn
首先先初始化循環變量:oracle
0: iconst_0 1: istore_1
這兩行代碼至關於 int i = 0
這句代碼(iconst_0 是數字 0,istore_1 就是表示局部變量1,這裏就是源碼裏的 i 了)app
5: iload_2 6: iload_0 7: if_icmpge 35
這三行意思就是 i 是否小於 10 ,小於則繼續往下執行,不然就跳到 編號爲 35的 return那裏也即跳出for循環了,因此這裏的實際意義是每次循環時新建一個StringBuilder,而後本次循環結束時返回StringBuilder的toString()的結果。 #####對比contactStringWithStringBuffer[在javac結果的122行]ide
public static java.lang.String contactStringWithStringBuffer(int); Code: 0: new #22 // class java/lang/StringBuffer 3: dup 4: invokespecial #23 // Method java/lang/StringBuffer."<init>":()V 7: astore_1 8: iconst_0 9: istore_2 10: iload_2 11: iload_0 12: if_icmpge 27 15: aload_1 16: iload_2 17: invokevirtual #24 // Method java/lang/StringBuffer.append:(I)Ljava/lang/StringBuffer; 20: pop 21: iinc 2, 1 24: goto 10 27: aload_1 28: invokevirtual #25 // Method java/lang/StringBuffer.toString:()Ljava/lang/String; 31: areturn
上面是先new StringBuilder,以後只是對這個StringBuilder進行append。 結論:當使用變量並循環拼接字符串時,應該使用StringBuilder的方式。oop