程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA編程入門知識 >> Java編譯器對於String常量表達式的優化

Java編譯器對於String常量表達式的優化

編輯:JAVA編程入門知識

  首先把問題擺出來,先看這個代碼

String a = "ab";
  String b = "a" + "b";
  System.out.println((a == b));

  打印結果會是什麼?類似這樣的問題,有人考過我,我也拿來考過別人(蠻好玩的,大家也可以拿來問人玩),一般答案會是以下幾種:

  1.true

  "a" + "b" 的結果就是"ab",這樣a,b都是"ab"了,內容一樣所以"相等",結果true

  一般Java新人如是答。

  2.false

  "a" + "a"會生成新的對象"aa",但是這個對象和String a = "ab";不同,(a == b)是比較對象引用,因此不相等,結果false

  對java的String有一定了解的通常這樣回答。

  3.true

  String a = "ab";創建了新的對象"ab"; 再執行String b = "a" + "b";結果b="ab",這裡沒有創建新的對象,而是從JVM字符串常量池中獲取之前已經存在的"ab"對象。因此a,b具有對同一個string對象的引用,兩個引用相等,結果true.

  能回答出這個答案的,基本已經是高手了,對java中的string機制比較了解。

  很遺憾,這個答案,是不夠准確的。或者說,根本沒有運行時計算b = "a" + "b";這個操作.實際上運行時只有String b = "ab";

  3的觀點適合解釋以下情況:

String a = "ab";
  String b = "ab";
  System.out.println((a == b));

  假如String b = "a" + "b";是在運行期執行,則3的觀點是無法解釋的。運行期的兩個string相加,會產生新的對象的。(本文後面對此有解釋)

  4.true

  下面是我的回答:編譯優化+ 3的處理方式 = 最後的true

  String b = "a" + "b";編譯器將這個"a" + "b"作為常量表達式,在編譯時進行優化,直接取結果"ab",這樣這個問題退化

String a = "ab";
  String b = "ab";
  System.out.println((a == b));

  然後根據3的解釋,得到結果true

  這裡有一個疑問就是String不是基本類型,像

int secondsOfDay = 24 * 60 * 60;

  這樣的表達式是常量表達式,編譯器在編譯時直接計算輕易理解,而"a" + "b" 這樣的表達式,string是對象不是基本類型,編譯器會把它當成常量表達式來優化嗎?

  下面簡單證實我的推斷,首先編譯這個類:

public class Test {
  private String a = "aa";
  }

  復制class文件備用,然後修改為

public class Test {
  private String a = "a" + "a";
  }

  再次編譯,用ue之類的文本編輯器打開,察看二進制內容,可以發現,兩個class文件完全一致,連一個字節都不差.

  ok,真相大白了.根本不存在運行期的處理String b = "a" + "b";這樣的代碼的問題,編譯時就直接優化掉了。

  下面進一步探討,什麼樣的string + 表達式會被編譯器當成常量表達式?

String b = "a" + "b";

  這個String + String被正式是ok的,那麼string + 基本類型呢?

String a = "a1";
  String b = "a" + 1;
  System.out.println((a == b)); //result = true
  String a = "atrue";
  String b = "a" + true;
  System.out.println((a == b)); //result = true
  String a = "a3.4";
  String b = "a" + 3.4;
  System.out.println((a == b)); //result = true

  可見編譯器對string + 基本類型是當成常量表達式直接求值來優化的。

  再注重看這裡的string都是"**"這樣的,我們換成變量來試試:

String a = "ab";
  String bb = "b";
  String b = "a" + bb;
  System.out.println((a == b)); //result = false

  這個好理解,"a" + bb中的bb是變量,不能進行優化。這裡很很好的解釋了為什麼3的觀點不正確,假如String+String的操作是在運行時進行的,則會產生新的對象,而不是直接從jvm的string池中獲取。

  再修改一下,把bb作為常量變量:

String a = "ab";
  final String bb = "b";
  String b = "a" + bb;
  System.out.println((a == b)); //result = true

  竟然又是true,編譯器的優化好厲害啊,呵呵,考慮下面這種情況:

String a = "ab";
  final String bb = getBB();
  String b = "a" + bb;
  System.out.println((a == b)); //result = false
  private static String getBB() {
  return "b";
  }

  看來java(包括編譯器和jvm)對string的優化,真的是到了極點了,string這個所謂的"對象",完全不可以看成一般的對象,java對string的處理近乎於基本類型,最大限度的優化了幾乎能優化的地方。

  
   另外感歎一下,string的+號處理,算是java語言裡面唯一的一個"運算符重載"(接觸過c++的人對這個不會生疏)吧?


 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved