一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務器之家 - 編程語言 - JAVA教程 - 區分java中String+String和String+char

區分java中String+String和String+char

2020-03-24 13:21lijiao JAVA教程

這篇文章主要向大家詳細區分了java中String+String和String+char,感興趣的小伙伴們可以參考一下

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

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

String str = "abc" + "/";

1、編譯器優化

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

?
1
String str = "abc/";

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

?
1
2
3
4
StringOne.java
String str1 = "abc" + '/';
String str2 = "abc" + "/";
System.out.println(str1 == str2);

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

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

然后查看生成的StringOne.s文件. 就會發現其中有這么幾行

?
1
2
3
4
5
6
7
8
9
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分析差異

現在我們換一個問法, 下面的代碼中stringAddString和stringAddChar方法有什么區別?

?
1
2
3
4
5
6
7
8
StringTwo
public static String stringAddString(String str1, String str2){
  return str1 + str2;
}
 
public static String stringAddChar(String str, char ch){
  return str + ch;
}

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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

現在, 我們已經可以很清楚的看出這兩個方法執行的流程了:

stringAddString

  • 創建一個StringBuilder對象
  • 使用append方法, 依次將兩個參數添加到剛才創建的StringBuilder中.
  • 調用toString方法.
  • return toString方法的返回值.

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

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

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

AbstractStringBuilder.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public AbstractStringBuilder append(char c) {
  ensureCapacityInternal(count + 1);  // 確保數組能夠容納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); // 拷貝字符串中的字符數組到本對象的字符數組中
  count += len;
  return this;
}

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

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

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

新的問題

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

?
1
2
3
4
5
6
String str1 = "abc" + "123"// 1
 
StringBuilder stringBuilder = new StringBuilder(); // 2
stringBuilder.append("abc");
stringBuilder.append("123");
String str2 = stringBuilder.toString();

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

以上就是本文的全部內容,幫助大家更好的區分java中String+String和String+char,希望對大家的學習有所幫助。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 欧美精品一区二区在线观看播放 | 图片亚洲va欧美va国产综合 | 免费被靠视频动漫 | 乳环贵妇堕落开发调教番号 | 秋霞网毛片 | 果冻传媒在线观看的 | 99 久久99久久精品免观看 | 四虎影院永久在线 | 亚洲视频一区二区在线观看 | 大东北chinesexxxx露脸 | 天天做日日做 | 99视频有精品视频免费观看 | 大又大又粗又爽女人毛片 | 91久久偷偷做嫩草影院免费看 | 免费的强动漫人物的 | 蹭蹭妈妈的朋友小说 | 亚洲免费一 | 无敌在线视频观看免费 | 国产伦精品一区二区三区免费观看 | 99精品视频免费观看 | 成人免费国产欧美日韩你懂的 | 4455永久在线观免费看片 | 艾秋麻豆果冻传媒老狼仙踪林 | 小寡妇好紧进去了好大看视频 | 午夜在线a亚洲v天堂网2019 | 亚洲国产欧美在线人成aaa | 国产欧美日韩视频在线观看一区二区 | 欧美老骚 | 亚洲骚图 | 国产精品久久久天天影视香蕉 | 人人艹在线视频 | 精品国产乱码久久久久久免费 | 天天操夜夜操狠狠操 | 小早川怜子视频在线观看 | 高跟丝袜hdvideossex | 日韩欧美国内 | 91精品国产91热久久p | 欧美日韩高清完整版在线观看免费 | 苍井空色欲迷墙 | 青春娱乐国产分类精品二 | 免费看黄色片的网站 |