久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Java-String那些事

 黃家v少 2018-04-11


String對(duì)于廣大程序員來(lái)說(shuō),,并不陌生,,是我們?cè)诰帉懗绦蛑薪?jīng)常使用到的對(duì)象。但是,,你真的對(duì)String了解嗎,,使用的方式對(duì)嗎?


接下來(lái),,筆者就對(duì)String來(lái)進(jìn)行全面的解析,,讓你對(duì)String有更深入的了解!

更重要的是,,面試的時(shí)候,,虐虐面試官!


String源碼(截取)


通過(guò)源碼,,可以看出String類被final修飾,,也就意味著String不能被繼承,它其中的方法都默認(rèn)被final修飾(此特性是final的特點(diǎn)),。也就是說(shuō)當(dāng)String對(duì)象創(chuàng)建之后,,就不能再修改此對(duì)象中存儲(chǔ)的字符串內(nèi)容,就是因?yàn)槿绱?,才說(shuō)String類型是不可變的(immutable)


在我們平常創(chuàng)建String對(duì)象時(shí),,在底層通過(guò)char數(shù)組來(lái)實(shí)現(xiàn)。


截取字符串:


拼接兩個(gè)字符串:


替換字符串中的內(nèi)容:

截取了String類中的三個(gè)常用方法,,從這三個(gè)方法的返回值中可以看出,,無(wú)論是substring()、concat()還是replace()方法,,他們對(duì)字符串的操作都不是在原有字符串上進(jìn)行的,,而是通過(guò)一系列操作生成了一個(gè)新的字符串對(duì)象。


這也符合了我們上面所說(shuō)的,,String類被final修飾不可改變,,String對(duì)象一單創(chuàng)建就固定不變了,對(duì)String對(duì)象的任何操作都不會(huì)改變?cè)瓕?duì)象,,只會(huì)新生成一個(gè)對(duì)象,。

image


創(chuàng)建String對(duì)象


在Java程序中,創(chuàng)建String對(duì)象有兩種形式,,一種叫做字面量形式,,例如:String str = 'jiaboyan';一種叫做構(gòu)造形式,,也就是我們通常的new對(duì)象,,例如:String str = new String('jiaboyan');


無(wú)論是字面量,,還是構(gòu)造形式,在我們編碼時(shí)都經(jīng)常使用,,尤其是前者,。但是,這兩種實(shí)現(xiàn)方式在性能和內(nèi)存上卻有著不小的差別,。


采用字面值的方式賦值:

執(zhí)行String str1 = 'jiaboyan',,程序會(huì)去字符串常量池中中查找是否存在'jiaboyan'。如果不存在,,則在字符串常量池中創(chuàng)建'jiaboyan',,并將“jiaboyan”的引用地址返回給str1,也就是說(shuō)str1拿到了字符串常量池中“jiaboyan”的引用,。如果存在,,則不創(chuàng)建任何字符串,直接將池中'jiaboyan'引用地址返回賦給所屬變量,。當(dāng)創(chuàng)建字符串對(duì)象str2時(shí),,字符串池中已經(jīng)存在'jiaboyan',此時(shí)會(huì)直接把對(duì)象'jiaboyan'的引用地址返回給str2,。


采用new關(guān)鍵字新建一個(gè)字符串對(duì)象:

采用new方式創(chuàng)建對(duì)象,,執(zhí)行String str1 = new String('jiaboyan'),程序會(huì)在字符串常量池中查找有沒有'jiaboyan'這個(gè)字符串,,如果有,,則不在字符串常量池中創(chuàng)建'jiaboyan',直接在堆中創(chuàng)建一個(gè)'jiaboyan'字符串對(duì)象,,然后將堆中的這個(gè)'jiaboyan'對(duì)象的地址返回給str1,;如果沒有,則首先在字符串常量池中創(chuàng)建一個(gè)'jiaboyan'字符串,,然后再在堆中創(chuàng)建一個(gè)'jiaboyan'字符串對(duì)象,,然后將堆中的這個(gè)'jiaboyan'對(duì)象的地址返回給str2。此時(shí),,str1和str2所指向不同的堆內(nèi)存區(qū)域,,使用==比較返回為false。


兩種創(chuàng)建方式比較:

根據(jù)前面的2個(gè)例子,,可以得出,當(dāng)我們?cè)趧?chuàng)建str1的對(duì)象時(shí),,實(shí)際上程序會(huì)去字符串常量池中去創(chuàng)建“jiaboyan”,,而當(dāng)程序執(zhí)行到str2時(shí),會(huì)首先檢查字符串常量池中是否存在,,若存在則直接在堆內(nèi)存中創(chuàng)建一個(gè)字符串對(duì)象,;若不存在,,則首先在字符串常量池中創(chuàng)建“jiaboyan”,再在堆內(nèi)存中創(chuàng)建字符串對(duì)象。所以,,當(dāng)兩者進(jìn)行比較時(shí),,實(shí)際上內(nèi)存地址是不同的。


編譯期確定:

str1和str2的原理跟第一個(gè)例子相同,,不在過(guò)多陳述,。在str3中,兩個(gè)字符串拼接起來(lái)合成一個(gè)字符串,,在編譯期做了拼接處理,,被解析成了一個(gè)字符串常量,所以str3在運(yùn)行期間是以一個(gè)整體'jiaboyan'在進(jìn)行比較,,結(jié)果為true;


使用javap命令,,可以查看到test3()在編譯期的處理情況?;蛘咄ㄟ^(guò)查看生成的.class文件,。

image


編譯期無(wú)法確定:

str1和str2的結(jié)果,上面的例子已經(jīng)說(shuō)明,。str1在編譯器可以確定,,只會(huì)在字符串常量池中創(chuàng)建。str2在運(yùn)行期,,會(huì)在堆中對(duì)象,。str3在編譯期無(wú)法確定內(nèi)容,所以編譯時(shí)候無(wú)法進(jìn)行優(yōu)化拼接,,直到運(yùn)行時(shí)才可確定,,并生成新的對(duì)象在堆中。


編譯期無(wú)法確定:

String str3 = str1 + str2在編譯器無(wú)法確定,,所以無(wú)法做拼接優(yōu)化,。只能等到真正運(yùn)行時(shí),才能確定,。所以當(dāng)str3 == 'jiaboyan'時(shí),,結(jié)果為false,因?yàn)橐粋€(gè)在堆中創(chuàng)建,,一個(gè)在字符串常量池中,。此外,str3雖然無(wú)法在堆中做拼接優(yōu)化,,但是str3在編譯期還是做了代碼優(yōu)化,,使用的是StringBuilder。具體,請(qǐng)看.class文件:

image

兩個(gè)在編譯期無(wú)法確認(rèn)的String,,在編譯后是通過(guò)StringBuilder對(duì)象的append()進(jìn)行處理的,,最后在調(diào)用toString()將結(jié)果返回給str3。所以,,在代碼中要么就使用全字符串拼接,,要不就別拼接。


編譯期確定:

回顧下final的含義,,當(dāng)用final修飾一個(gè)類時(shí),,表明這個(gè)類不能被繼承。當(dāng)用final修飾一個(gè)變量時(shí),,如果是基本數(shù)據(jù)類型的變量,,則其數(shù)值一旦在初始化之后便不能更改;如果是引用類型的變量,,則在對(duì)其初始化之后便不能再讓其指向另一個(gè)對(duì)象,。


在編譯期間,由于str1和str2使用了final修飾,,所以編譯器知道該對(duì)象不可改變,,所以當(dāng)編譯到str3時(shí),會(huì)進(jìn)行代碼優(yōu)化,,直接將str1和str2進(jìn)行字符串拼接,,形成一個(gè)“jiaboyan”字符串。當(dāng)執(zhí)行比較時(shí)為true.

image


編譯期無(wú)法確定:

與上面的例子類似,,兩個(gè)變量str1和str2都用了final修飾,。不同的是,str2的值是通過(guò)方法來(lái)獲得,。在編譯期間,,無(wú)法確定最終的值,只能在運(yùn)行時(shí)確定,,因此str3和“jiaboyan”指向的是不同的內(nèi)存區(qū)域,。str3指向了堆中的內(nèi)存地址,而“jiaboyan”指向的是字符創(chuàng)常量池中,。


編譯期無(wú)法確定:

與前面的例子類似,,本例子算是對(duì)上面的一個(gè)總結(jié)。在我們的程序中,,是直接拼接字符串,,還是字符串和變量共同連接使用。


通過(guò),,編譯后的class文件來(lái)看,,str3中使用了StringBuild來(lái)處理字符串之間的拼接,,最后在通過(guò)toString的方式來(lái)返回給str3;


在字符串變量中,使用 + 連接符進(jìn)行連接時(shí),,在編譯期間,連接操作會(huì)將最左側(cè)的字符串拼接,,并創(chuàng)建StringBuilder對(duì)象,,然后依次對(duì)右邊進(jìn)行append操作,最后將StringBuilder對(duì)象通過(guò)toString()方法轉(zhuǎn)換成String對(duì)象,。當(dāng)使用 + 進(jìn)行多個(gè)字符串連接時(shí),,實(shí)際上是產(chǎn)生了一個(gè)StringBuilder對(duì)象和一個(gè)String對(duì)象。

image


equals() 和 ==


關(guān)于 == 和 equals() 的使用,,也是我們面試/日常工作中經(jīng)常遇到的,。對(duì)于這兩種比較方式,我們需要有一個(gè)清晰的理解,。


對(duì)于 == 來(lái)說(shuō),,如果比較的是基本類型,例如:byte,short,char,int,long,float,double,boolean,,那么實(shí)際比較的就是該變量真實(shí)值是否相同,。但,如果比較的是引用類型,,例如:new ArrayList(),new Obeject,,那么實(shí)際比較的該變量實(shí)際在內(nèi)存中的地址。


對(duì)于equals()來(lái)說(shuō),,equals()是基類Object中定義的方法,,所有對(duì)象都默認(rèn)繼承該類,所以也就默認(rèn)繼承了equals()方法,。對(duì)于默認(rèn)equals()來(lái)說(shuō),,實(shí)際比較的兩個(gè)對(duì)象在內(nèi)存中的地址是否相同。


值得注意的是,,由于equals()方法可以被重寫,,所以當(dāng)類中對(duì)equals()重寫時(shí)候,需要單獨(dú)關(guān)注,。例如:String類中就對(duì)對(duì)equals()進(jìn)行了重寫,,實(shí)際比較的就是兩個(gè)字符串中內(nèi)容是否相同,而不是真實(shí)的內(nèi)存地址,。


String.intern()


在String類中,,有一個(gè)intern()方法,該方法的作用是將在堆中的字符串,,copy一份存放到字符串常量池中,,設(shè)計(jì)的初衷其實(shí)是為了節(jié)省內(nèi)存的使用,提高程序的性能,可以讓程序重用String,。


代碼如下:

測(cè)試結(jié)果:


使用intern()方法的耗時(shí),,要比不使用intern()的耗時(shí)更長(zhǎng);


平均來(lái)看:1800ms 5500ms


在Java1.6中,,String.intern()在調(diào)用后,,會(huì)將在堆中生成的字符串,copy一份到字符串常量池中,,進(jìn)而在常量池中生成了一個(gè)新的對(duì)象,;而在Java1.7中,String.intern()有所改變,,不會(huì)在常量池中新生成對(duì)象,,而是將在堆中的引用復(fù)制到常量池中。


將一下代碼,,分別在Java1.6和Java1.7下去執(zhí)行:

測(cè)試結(jié)果如下:

image



《可伸縮服務(wù)架構(gòu):框架與中間件》是《分布式服務(wù)架構(gòu):原理,、設(shè)計(jì)與實(shí)戰(zhàn)》的姐妹篇,本書與上冊(cè)結(jié)合后可覆蓋保證線上高并發(fā)服務(wù)的各個(gè)主題:一致性,、高性 能,、高可用、可伸縮,、可擴(kuò)展,、敏捷性等。


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多