日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

String类型的认识以及编译器优化

發(fā)布時間:2023/12/31 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 String类型的认识以及编译器优化 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Java中String不是基本類型,但是有些時候和基本類型差不多,如String b =?"tao"?;?可以對變量直接賦值,而不用?new?一個對象(當(dāng)然也可以用?new)。所以String這個類型值得好好研究下。

Java中的變量和基本類型的值存放于棧內(nèi)存,而new出來的對象本身存放于堆內(nèi)存,指向?qū)ο蟮囊眠€是存放在棧內(nèi)存。例如如下的代碼:

int??i=1;

????String?s?=??new??String(?"Hello World"?);

變量i和s以及1存放在棧內(nèi)存,而s指向的對象”Hello World”存放于堆內(nèi)存。

?

?

?

?

棧內(nèi)存的一個特點是數(shù)據(jù)共享,這樣設(shè)計是為了減小內(nèi)存消耗,前面定義了i=1,i和1都在棧內(nèi)存內(nèi),如果再定義一個j=1,此時將j放入棧內(nèi)存,然后查找棧內(nèi)存中是否有1,如果有則j指向1。如果再給j賦值2,則在棧內(nèi)存中查找是否有2,如果沒有就在棧內(nèi)存中放一個2,然后j指向2。也就是如果常量在棧內(nèi)存中,就將變量指向該常量,如果沒有就在該棧內(nèi)存增加一個該常量,并將變量指向該常量。

?

?

如果j++,這時指向的變量并不會改變,而是在棧內(nèi)尋找新的常量(比原來的常量大1),如果棧內(nèi)存有則指向它,如果沒有就在棧內(nèi)存中加入此常量并將j指向它。這種基本類型之間比較大小和我們邏輯上判斷大小是一致的。如定義i和j是都賦值1,則i==j結(jié)果為true。==用于判斷兩個變量指向的地址是否一樣。i==j就是判斷i指向的1和j指向的1是同一個嗎?當(dāng)然是了。對于直接賦值的字符串常量(如String s=“Hello World”;中的Hello World)也是存放在棧內(nèi)存中,而new出來的字符串對象(即String對象)是存放在堆內(nèi)存中。如果定義String s=“Hello World”和String w=“Hello World”,s==w嗎?肯定是true,因為他們指向的是同一個Hello World。

?

?

堆內(nèi)存沒有數(shù)據(jù)共享的特點,前面定義的String?s?=??new??String(?"Hello World"?);后,變量s在棧內(nèi)存內(nèi),Hello World?這個String對象在堆內(nèi)存內(nèi)。如果定義String w =?new??String(?"Hello World"?);,則會在堆內(nèi)存創(chuàng)建一個新的String對象,變量w存放在棧內(nèi)存,w指向這個新的String對象。堆內(nèi)存中不同對象(指同一類型的不同對象)的比較如果用==則結(jié)果肯定都是false,比如s==w?當(dāng)然不等,s和w指向堆內(nèi)存中不同的String對象。如果判斷兩個String對象相等呢?用equals方法。

?

?

?

說了這么多只是說了這道題的鋪墊知識,還沒進入主題,下面分析這道題。?MESSAGE?成員變量及其指向的字符串常量肯定都是在棧內(nèi)存里的,變量?a?運算完也是指向一個字符串“?taobao?”啊?是不是同一個呢?這涉及到編譯器優(yōu)化問題。對于字符串常量的相加,在編譯時直接將字符串合并,而不是等到運行時再合并。也就是說

String a =??"tao"?+?"bao"?;和String a =??"taobao"?;編譯出的字節(jié)碼是一樣的。所以等到運行時,根據(jù)上面說的棧內(nèi)存是數(shù)據(jù)共享原則,a和MESSAGE指向的是同一個字符串。而對于后面的(b+c)又是什么情況呢?b+c只能等到運行時才能判定是什么字符串,編譯器不會優(yōu)化,想想這也是有道理的,編譯器怕你對b的值改變,所以編譯器不會優(yōu)化。運行時b+c計算出來的"taobao"和棧內(nèi)存里已經(jīng)有的"taobao"是一個嗎?不是。b+c計算出來的"taobao"應(yīng)該是放在堆內(nèi)存中的String對象。這可以通過System.?out?.println( (b+c)==MESSAGE?);的結(jié)果為false來證明這一點。如果計算出來的b+c也是在棧內(nèi)存,那結(jié)果應(yīng)該是true。Java對String的相加是通過StringBuffer實現(xiàn)的,先構(gòu)造一個StringBuffer里面存放”tao”,然后調(diào)用append()方法追加”bao”,然后將值為”taobao”的StringBuffer轉(zhuǎn)化成String對象。StringBuffer對象在堆內(nèi)存中,那轉(zhuǎn)換成的String對象理所應(yīng)當(dāng)?shù)囊彩窃诙褍?nèi)存中。下面改造一下這個語句System.?out.println( (b+c).intern()==?MESSAGE?);結(jié)果是true,?intern()?方法會先檢查?String?池?(?或者說成棧內(nèi)存?)?中是否存在相同的字符串常量,如果有就返回。所以?intern()返回的就是MESSAGE指向的"taobao"。再把變量b和c的定義改一下,

final??String?b =??"tao"?;

?????????final??String?c =??"bao"?;

????????????

???????System.?out?.println( (b+c)==?MESSAGE?);

現(xiàn)在b和c不可能再次賦值了,所以編譯器將b+c編譯成了”taobao”。因此,這時的結(jié)果是true。

在字符串相加中,只要有一個是非final類型的變量,編譯器就不會優(yōu)化,因為這樣的變量可能發(fā)生改變,所以編譯器不可能將這樣的變量替換成常量。例如將變量b的final去掉,結(jié)果又變成了false。這也就意味著會用到StringBuffer對象,計算的結(jié)果在堆內(nèi)存中。

????如果對指向堆內(nèi)存中的對象的String變量調(diào)用intern()會怎么樣呢?實際上這個問題已經(jīng)說過了,(b+c).intern(),b+c的結(jié)果就是在堆內(nèi)存中。對于指向棧內(nèi)存中字符串常量的變量調(diào)用intern()返回的還是它自己,沒有多大意義。它會根據(jù)堆內(nèi)存中對象的值,去查找String池中是否有相同的字符串,如果有就將變量指向這個string池中的變量。

String a = "tao"+"bao";

???????String b = new String("taobao");

?????

??????System.out.println(a==MESSAGE);?//true

??????System.out.println(b==MESSAGE);??//false

?????

??????b = b.intern();

??????System.out.println(b==MESSAGE); //true

System.?out?.println(a==a.intern());??//true

轉(zhuǎn)載于:https://www.cnblogs.com/nxjblog/p/10574550.html

總結(jié)

以上是生活随笔為你收集整理的String类型的认识以及编译器优化的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。