国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

從字節碼角度看String、StringBuffer、StringBuilder的不同

wua_wua2012 / 2280人閱讀

摘要:官方說明將一個或多個類文件進行分解。顯示靜態常量為每個類中的方法打印反匯編代碼例如字節碼指令組成。在結果的行直接進行多次的拼接看看最后編譯會是神馬的這句話是對應聲明了一個,然后每次拼接實際使用的是的方法。

Oracle官方說明:

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的不同 測試類
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 來獲得字節碼信息
Compiled from "Test.java"
public class Test {
  public Test();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."":()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."":()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."":()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."":()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."":()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行]
  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行]
  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."":()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."":()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       

首先先初始化循環變量:

         0: iconst_0      
         1: istore_1

這兩行代碼相當于 int i = 0 這句代碼(iconst_0 是數字 0,istore_1 就是表示局部變量1,這里就是源碼里的 i 了)

       5: iload_2
       6: iload_0
       7: if_icmpge     35

這三行意思就是 i 是否小于 10 ,小于則繼續往下執行,否則就跳到 編號為 35的 return那里也即跳出for循環了,所以這里的實際意義是每次循環時新建一個StringBuilder,然后本次循環結束時返回StringBuilder的toString()的結果。

對比contactStringWithStringBuffer[在javac結果的122行]
  public static java.lang.String contactStringWithStringBuffer(int);
    Code:
       0: new           #22                 // class java/lang/StringBuffer
       3: dup           
       4: invokespecial #23                 // Method java/lang/StringBuffer."":()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的方式。

main方法中的測試結果也可以看出使用String、StringBuilder、StringBuffer分別進行10000次的百次字符拼接,StringBuilder的性能遠遠高于StringBuffer和String。【StringBuffer是線程安全的嗎,所以損耗一些性能但是也優于String,主要是因為每次new StringBuilder的代價比較大】
我是廣告

本人的直播課程在 7 月份就要開始了,希望小伙伴們支持一下,現在報名有優惠噢

https://segmentfault.com/l/15...

https://segmentfault.com/l/15...

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/67223.html

相關文章

  • 【Java系列】JVM角度深度解析Java核心類String不可變特性

    摘要:性能,大量運用在哈希的處理中,由于的不可變性,可以只計算一次哈希值,然后緩存在內部,后續直接取就好了。這是目前的一個底層字節碼的實現,那么是不是沒有使用或者的必要了呢。 凱倫說,公眾號ID: KailunTalk,努力寫出最優質的技術文章,歡迎關注探討。 1. 前言 最近看到幾個有趣的關于Java核心類String的問題。 String類是如何實現其不可變的特性的,設計成不可變的好處...

    afishhhhh 評論0 收藏0
  • 最最最常見Java面試題總結——第二周

    摘要:與都繼承自類,在中也是使用字符數組保存字符串,,這兩種對象都是可變的。采用字節碼的好處語言通過字節碼的方式,在一定程度上解決了傳統解釋型語言執行效率低的問題,同時又保留了解釋型語言可移植的特點。 String和StringBuffer、StringBuilder的區別是什么?String為什么是不可變的? String和StringBuffer、StringBuilder的區別 可變性...

    yearsj 評論0 收藏0
  • Java編程中那些再熟悉不過知識點(持續更新)

    摘要:語言通過字節碼的方式,在一定程度上解決了傳統解釋型語言執行效率低的問題,同時又保留了解釋型語言可移植的特點。有針對不同系統的特定實現,,,目的是使用相同的字節碼,它們都會給出相同的結果。項目主要基于捐贈的源代碼。 本文來自于我的慕課網手記:Java編程中那些再熟悉不過的知識點,轉載請保留鏈接 ;) 1. 面向對象和面向過程的區別 面向過程 優點: 性能比面向對象高。因為類調用時需要實例...

    taowen 評論0 收藏0
  • 超詳細Java面試題總結(一)之Java基礎知識篇

    摘要:最近在備戰面試的過程中,整理一下面試題。成員變量如果沒有被賦初值,則會自動以類型的默認值而賦值一種情況例外被修飾但沒有被修飾的成員變量必須顯示地賦值而局部變量則不會自動賦值。   最近在備戰面試的過程中,整理一下面試題。大多數題目都是自己手敲的,網上也有很多這樣的總結。自己感覺總是很亂,所以花了很久把自己覺得重要的東西總結了一下。 面向對象和面向過程的區別 面向過程:  優點:性能比面...

    vpants 評論0 收藏0
  • StringStringBuilder、StringBuffer 拼接測試

    摘要:測試拼接速度測試的結果在循環中,拼接字符串的速度遠低于和利用查看字節碼文件,尋找其中的差異命令行執行結果可以看出,拼接的時候也是通過的方法進行拼接的產生差異的原因是,在每次循環中,拼接的時候都了一個是線程安全的,只比稍慢了一點若不是 String、StringBuilder、StringBuffer 測試拼接速度 @Test public void testString() { ...

    20171112 評論0 收藏0

發表評論

0條評論

wua_wua2012

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<