欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

區(qū)分java中String+String和String+char

 更新時間:2016年01月24日 09:19:31   投稿:lijiao  
這篇文章主要向大家詳細區(qū)分了java中String+String和String+char,感興趣的小伙伴們可以參考一下

我們來考慮一個關(guān)于java中String的問題: "abc" + '/'和 "abc" + "/"的區(qū)別. 通過這個例子, 我們可以順便練習(xí)一下JDK工具中javap的用法, 原問題是這樣的:

把斜杠/當作字符或字符串有什么區(qū)別呢?
一個是當作基本數(shù)據(jù)類型char,一個是對象String。具體有什么區(qū)別呢?
當作字符效率會更高嗎?
String str = "abc" + '/';

String str = "abc" + "/";

1、編譯器優(yōu)化

首先大家應(yīng)該知道, 上面那兩句效果是一樣的, 因為編譯器會把上面那兩句都優(yōu)化成下面的樣子:

String str = "abc/";

我們可以通過javap證明這一點. 關(guān)于javap, 可以參考《每個Java開發(fā)者都應(yīng)該知道的5個JDK工具》. 我們首先創(chuàng)建一個類: StringOne, 在主方法中填入下面的代碼:

StringOne.java
String str1 = "abc" + '/';
String str2 = "abc" + "/";
System.out.println(str1 == str2);

編譯并運行, 輸出結(jié)果為true. 接下來, 該我們的javap登場了, 在命令行中輸入下面的命令:

javap -v -l StringOne.class > StringOne.s

然后查看生成的StringOne.s文件. 就會發(fā)現(xiàn)其中有這么幾行

StringOne.s
#2 = String       #20      // abc/
...
#20 = Utf8        abc/
...
0: ldc      #2         // String abc/
2: astore_1
3: ldc      #2         // String abc/
5: astore_2

說明str1和str2都引用字符串"abc\".

2、使用javap分析差異

現(xiàn)在我們換一個問法, 下面的代碼中stringAddString和stringAddChar方法有什么區(qū)別?

StringTwo
public static String stringAddString(String str1, String str2){
  return str1 + str2;
}

public static String stringAddChar(String str, char ch){
  return str + ch;
}

這次再使用javap進行反編譯, 生成文件的部分內(nèi)容如下所示

StringTwo.s
public java.lang.String stringAddString(java.lang.String, java.lang.String);
 descriptor: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
 flags: ACC_PUBLIC
 Code:
  stack=2, locals=3, args_size=3
    0: new      #2         // class java/lang/StringBuilder
    3: dup
    4: invokespecial #3         // Method java/lang/StringBuilder."< init>":()V
    7: aload_1
    8: invokevirtual #4         // Method java/lang/StringBuilder. append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   11: aload_2
   12: invokevirtual #4         // Method java/lang/StringBuilder. append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   15: invokevirtual #5         // Method java/lang/StringBuilder. toString:()Ljava/lang/String;
   18: areturn

public java.lang.String stringAddChar(java.lang.String, char);
 descriptor: (Ljava/lang/String;C)Ljava/lang/String;
 flags: ACC_PUBLIC
 Code:
  stack=2, locals=3, args_size=3
    0: new      #2         // class java/lang/StringBuilder
    3: dup
    4: invokespecial #3         // Method java/lang/StringBuilder."<init>":()V
    7: aload_1
    8: invokevirtual #4         // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   11: iload_2
   12: invokevirtual #6         // Method java/lang/StringBuilder.append:(C)Ljava/lang/StringBuilder;
   15: invokevirtual #5         // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   18: areturn

現(xiàn)在, 我們已經(jīng)可以很清楚的看出這兩個方法執(zhí)行的流程了:

stringAddString

  • 創(chuàng)建一個StringBuilder對象
  • 使用append方法, 依次將兩個參數(shù)添加到剛才創(chuàng)建的StringBuilder中.
  • 調(diào)用toString方法.
  • return toString方法的返回值.

stringAddChar的過程和stringAddString一樣, 只是在第二次調(diào)用append方法時stringAddString的參數(shù)是String類型, 而stringAddChar的參數(shù)是char類型.

3、StringBuilder類的append(char)方法和append(String)方法

這里,我們直接查看源碼就好了(我的是jdk1.8.0_60附帶的源碼)。 注意,雖然文檔上顯示StringBuilder繼承自O(shè)bject, 但是從源碼來看, 它是繼承自抽象類AbstractStringBuilder的。而且append方法是由AbstractStringBuilder實現(xiàn)的。

AbstractStringBuilder.java

public AbstractStringBuilder append(char c) {
  ensureCapacityInternal(count + 1);  // 確保數(shù)組能夠容納count+1個字符
  value[count++] = c;
  return this;
}

public AbstractStringBuilder append(String str) {
  if (str == null)
    return appendNull();
  int len = str.length();
  ensureCapacityInternal(count + len);
  str.getChars(0, len, value, count); // 拷貝字符串中的字符數(shù)組到本對象的字符數(shù)組中
  count += len;
  return this;
}

剩下的就不再貼出來了。String.getChars(int, int, char[], int)最終依賴于public static native void arraycopy(Object, int, Object, int, int)。也就是說有可能是C語言寫的,在拷貝大型數(shù)組時效率應(yīng)該會比java寫的程序好一些。 那么,現(xiàn)在說說我的理解:

從直接內(nèi)存來說, 由于String中包含char數(shù)組, 而數(shù)組應(yīng)該是有長度字段的, 同時String類還有一個int hash屬性, 再加上對象本身會占用額外的內(nèi)存存儲其他信息,所以字符串會多占用一些內(nèi)存. 但是如果字符串非常長, 那么這些內(nèi)存開銷差不多就可以忽略了; 而如果像"/"這種情況, 字符串比較(非常)短,那么就很可能有許多個共享引用來分擔(dān)這些內(nèi)存開銷, 那么多余的內(nèi)存開銷還是可以忽略的.

從調(diào)用堆棧上, 由于這里String只比char多了一兩層函數(shù)調(diào)用,所以如果不考慮函數(shù)調(diào)用開銷(包括時間和空間), 應(yīng)該差不多;考慮函數(shù)調(diào)用開銷, 應(yīng)該 "abc" + '/'更好一些; 但是當需要連接若干個字符時(感覺這種情況應(yīng)該更常見吧?), 由于使用char需要循環(huán)好多次才能完成連接, 調(diào)用的函數(shù)次數(shù)只會比使用String更多. 同時拷貝也不會比String直接拷貝一個數(shù)組更快. 所以這個時候就變成了"abc" + "/"吞吐量更大.
現(xiàn)在感覺這個問題像是在問: 讀寫文件時使用系統(tǒng)調(diào)用效率高, 還是使用標準函數(shù)庫中的IO庫效率高. 個人感覺, 雖然標準IO庫最后還得調(diào)用系統(tǒng)調(diào)用, 而且這之間會產(chǎn)生一些臨時變量, 以及更深層次的調(diào)用堆棧, 但是由于IO庫的緩沖等機制, 所以IO庫的吞吐量會更大, 而系統(tǒng)調(diào)用的實時性會好一些. 同樣, 雖然String類會多幾個字段, 有更深層次的函數(shù)堆棧, 但是由于緩存以及更直接的拷貝, 吞吐量應(yīng)該會更好一些.

新的問題

從上面javap的反編譯代碼來看, 兩個String相加, 會變成向StringBuilder中append字符串. 那么理論上, 下面哪段代碼的效率好呢?

String str1 = "abc" + "123";  // 1

StringBuilder stringBuilder = new StringBuilder(); // 2
stringBuilder.append("abc");
stringBuilder.append("123");
String str2 = stringBuilder.toString();

這個問題就留給大家思考吧!

以上就是本文的全部內(nèi)容,幫助大家更好的區(qū)分java中String+String和String+char,希望對大家的學(xué)習(xí)有所幫助。

相關(guān)文章

  • java中子類繼承父類,程序運行順序的深入分析

    java中子類繼承父類,程序運行順序的深入分析

    本篇文章是對java中子類繼承父類,程序運行順序進行了詳細的分析介紹,需要的朋友參考下
    2013-06-06
  • Netty分布式解碼器讀取數(shù)據(jù)不完整的邏輯剖析

    Netty分布式解碼器讀取數(shù)據(jù)不完整的邏輯剖析

    這篇文章主要為大家介紹了Netty分布式解碼器讀取數(shù)據(jù)不完整的邏輯剖析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-03-03
  • Java中的鎖與鎖的狀態(tài)升級詳細解讀

    Java中的鎖與鎖的狀態(tài)升級詳細解讀

    這篇文章主要介紹了Java中的鎖與鎖的狀態(tài)升級詳細解讀,Java 1.6以后官方針對鎖的優(yōu)化,主要是增加了兩種新的鎖:偏向鎖和輕量級鎖,再加上本身重量級鎖,那么鎖基本上可以大致分為這三種,它們之間的區(qū)別主要是體現(xiàn)在等待時間上面,需要的朋友可以參考下
    2024-01-01
  • SpringBoot通過源碼探究靜態(tài)資源的映射規(guī)則實現(xiàn)

    SpringBoot通過源碼探究靜態(tài)資源的映射規(guī)則實現(xiàn)

    這篇文章主要介紹了SpringBoot通過源碼探究靜態(tài)資源的映射規(guī)則實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05
  • Spring Boot2.x如何自定義Endpoint

    Spring Boot2.x如何自定義Endpoint

    這篇文章主要介紹了Spring Boot2.x如何自定義Endpoint,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-02-02
  • JAVA獲取Image的三種方式

    JAVA獲取Image的三種方式

    這篇文章主要介紹了JAVA獲取Image的三種方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • Java編程獲取當前屏幕分辨率的方法示例

    Java編程獲取當前屏幕分辨率的方法示例

    這篇文章主要介紹了Java編程獲取當前屏幕分辨率的方法,涉及java針對系統(tǒng)硬件信息的相關(guān)操作技巧,需要的朋友可以參考下
    2017-08-08
  • Java 集合中關(guān)于Iterator和ListIterator的用法說明

    Java 集合中關(guān)于Iterator和ListIterator的用法說明

    這篇文章主要介紹了Java 集合中關(guān)于Iterator和ListIterator的用法說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • 為什么阿里巴巴要求日期格式化時必須有使用y表示年

    為什么阿里巴巴要求日期格式化時必須有使用y表示年

    這篇文章主要介紹了為什么阿里巴巴要求日期格式化時必須有使用y表示年,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • 解決spring cloud gateway 獲取body內(nèi)容并修改的問題

    解決spring cloud gateway 獲取body內(nèi)容并修改的問題

    這篇文章主要介紹了解決spring cloud gateway 獲取body內(nèi)容并修改的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12

最新評論