亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Java String 在JVM中的思考

系統 1999 0
    
      package com;

/**
 * @author longgangbai
 * 
 */
public class StringTest {
	public static void main(String[] args) {
		String a = "ab";// 創建了一個對象,并加入字符串池中
		System.out.println("String a = \"ab\";");
		String b = "cd";// 創建了一個對象,并加入字符串池中
		System.out.println("String b = \"cd\";");
		String c = "abcd";// 創建了一個對象,并加入字符串池中

		String d = "ab" + "cd";
		// 如果d和c指向了同一個對象,則說明d也被加入了字符串池
		if (d == c) {
			System.out.println("\"ab\"+\"cd\" 創建的對象 \"加入了\" 字符串池中"); //答案
		}
		// 如果d和c沒有指向了同一個對象,則說明d沒有被加入字符串池
		else {
			System.out.println("\"ab\"+\"cd\" 創建的對象 \"沒加入\" 字符串池中");
		}
		String e = a + "cd";
		// 如果e和c指向了同一個對象,則說明e也被加入了字符串池
		if (e == c) {
			System.out.println(" a  +\"cd\" 創建的對象 \"加入了\" 字符串池中");
		}
		// 如果e和c沒有指向了同一個對象,則說明e沒有被加入字符串池
		else {
			System.out.println(" a  +\"cd\" 創建的對象 \"沒加入\" 字符串池中");//答案.
		}
		String f = "ab" + b;
		// 如果f和c指向了同一個對象,則說明f也被加入了字符串池
		if (f == c) {
			System.out.println("\"ab\"+ b   創建的對象 \"加入了\" 字符串池中");
		}
		// 如果f和c沒有指向了同一個對象,則說明f沒有被加入字符串池
		else {
			System.out.println("\"ab\"+ b   創建的對象 \"沒加入\" 字符串池中");//答案
		}

		String g = a + b;
		// 如果g和c指向了同一個對象,則說明g也被加入了字符串池
		if (g == c) {
			System.out.println(" a  + b   創建的對象 \"加入了\" 字符串池中"); 
		}
		// 如果g和c沒有指向了同一個對象,則說明g沒有被加入字符串池
		else {
			System.out.println(" a  + b   創建的對象 \"沒加入\" 字符串池中");//答案
		}
	}
}

    
  

? java編譯器對string常量表達式的處理和優化

sun的編譯器,jdk1.5是通過的如下:

?

?

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

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++的人對這個不會陌生)吧?

?

?

網友A:

第三點其實是正確的哦, 你所說的問題在于"a"+"b"是什么時候被執行的,但是并不能解釋引用a為什么是==引用b的,其實你想說的是string的+操作是在編譯期執行,這個確實是你正確的,從你的例子中也可以看出來。

但是如果要解釋a==b是true這個問題還是要用第3點解釋哦,所以第3點并沒有錯,這是千真萬確的,但是你對+操作的執行時期的描述也是正確的,這兩個應該是一個整體,而不是對立的。

String a = "ab";
String b = "ab";
System.out.println((a == b));
問題還是那樣,結果為什么是true,必須用第3點來解釋,而且這也是深入淺出jvm中的觀點。

?

?

直聽傳聞說法是:

SUN JDK 的 javac 是優化最多的, 編譯速度也慢.
IBM jikes 編譯速度快, 但沒什么優化.
Eclipse JDT Compiler 是從 VA4J Compiler 演化來的, 增量編譯很強, 優化也有, 相對JDK少.
GNU GCJ 不清楚, 不過還不成熟, 研究意義似乎不大.

不過我也沒怎么接觸過jikes, 樓主有空不妨用別的編譯器試試.

?

?

網友M:

?

恩,就是這個意思,我的表述不是很清晰。
我所說的第三點錯,并不是說第三點的解釋方式有問題,而是第三點闡述的"a"+"b"是運行期被執行不正確,而是第4點鐘的編譯器執行優化。
第三點中闡述的jvm對string的處理我沒有異議,呵呵,所以我在第4點中根本沒有解釋
String a = "ab";
String b = "ab";
System.out.println((a == b));
結果為什么是true,因為基本能想到第3點或第4點人,肯定非常清楚這里的true是怎么來的,呵呵。

第4點,其實是建立在第3點闡述的jvm對string的處理機制的基礎上的。先執行4優化,再執行3的機制,最后才能得到true這么一個結果。

?

修改了一下文檔的內容,將3的闡述改的清楚了一些。

實際這里存在兩個問題
1.?? 3解釋下面為true的問題
String a = "ab";
String b = "ab";
System.out.println((a == b));
?? 但是3的錯誤在于3中認為在運行期String b = "a"+"b";可以等同于String b = "ab";
2.?? 4通過編譯器優化的解釋解決了
String b = "a"+"b";等同于String b = "ab";的問題

?

?

還有對于jvm對string的處理和優化,我的感覺(還不確定,請大家指正)是這樣,jvm里面的string池,似乎只使用于兩個情況:

1.在編譯后的*.class文件里面定義的"abc"這樣的"直接"常量
?? 對于new String(), String + String/基本類型,toString()方法之類生成的string不是從string池里面取,而是直接生成新的string類。
2.調用string的intern()方法
?? 這個算是"強制"加入池吧

?

?

?

?

String這個東西也挺搞的,看了這個帖子,才知道我昨天做了一道題目錯了。:(
立即寫了個小程序測試:

Java代碼 復制代碼 ? 收藏代碼
    
      	public static void main(String[] args) {
		String s1 = "ab";
		String s2="a"+"b";
		System.out.println((s1==s2)+":"+(s1.equals(s2)));
		StringBuffer sb1=new StringBuffer("ab");
		StringBuffer sb2=new StringBuffer().append("a").append("b");
		System.out.println((sb1==sb2)+":"+(sb1.equals(sb2)));
	}

    
  


結果是
true:true
false:false

對于StringBuffer,只有引用相同,==和equals()才會成立。我看了equals()源碼,直接就是返回==比較的結果。
對于String,正如樓主的編譯器優化的說法,我再寫了一個程序:

Java代碼 復制代碼 ? 收藏代碼
    
      	private static String getString(){
		return "b";
	}
	public static void main(String[] args) {
		String s1 = "ab";
		String s2="a"+getString();
		System.out.println((s1==s2)+":"+(s1.equals(s2)));
	}

    
  


結果:
false:true

這個程序運行時產生的String對象是equals的,但==不成立。

?

Java String 在JVM中的思考


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 精品视频一区二区 | 久青草国产观看在线视频 | 久久精品国产精品2020 | 国产日韩综合 | 一区二区三区毛片免费 | 四虎影视黄色 | 久久久精品成人免费看 | 亚洲天堂福利视频 | 国产乱码精品一区二区三上 | 国产精品不卡在线 | 国产精品蜜臀 | 亚洲久久在线 | 26uuu精品一区二区 | 国语精品视频在线观看不卡 | 国产亚洲精品网站 | 久操福利 | 中文字幕一区二区视频 | 久久精品2 | 日本玖玖 | 亚洲精品一区二区三区在线看 | 精品日本一区二区 | 奇米色第四色 | 欧美日韩在线播放一区二区三区 | 青草福利视频 | 中文字幕亚洲视频 | 国产一区二区三区久久 | 巨骚综合网 | 欧美一级高清片在线 | 女人16一毛片 | 久久er国产精品免费观看1 | 草视频在线观看 | 99在线国产视频 | 亚洲成a人片毛片在线 | 亚洲第二页 | 交换国产精品视频一区 | 日韩伦理一区 | 国产成人在线视频网站 | 香蕉久久a毛片 | 国产欧美在线不卡 | 精品香蕉视频 | 视频免费1区二区三区 |