亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

首頁(yè) Java Java基礎(chǔ) 洞察 String字串

洞察 String字串

Dec 28, 2020 pm 05:27 PM

java基礎(chǔ)教學(xué)欄位介紹洞察String字串

洞察 String字串

#推薦(免費(fèi)):java基礎(chǔ)教學(xué)

#實(shí)作原理

##在Java6 以及在先前的版本中,String 物件是對(duì)char 陣列進(jìn)行了封裝實(shí)作的對(duì)象,主要有四個(gè)成員變數(shù):char 陣列、偏移量offset、字元數(shù)量count、雜湊值hash。

從 Java7 版本開(kāi)始到 Java8 版本,String 類別中不再有 offset 和 count 兩個(gè)變數(shù)了。這樣的好處是 String 物件佔(zhàn)用的記憶體稍微少了些。

從 Java9 版本開(kāi)始,將 char[]字段改為 byte[]字段,又維護(hù)了一個(gè)新的屬性 coder,它是一個(gè)編碼格式的標(biāo)識(shí)。

一個(gè) char 字元佔(zhàn) 16 位,2 個(gè)位元組。這個(gè)情況下,儲(chǔ)存單字節(jié)編碼內(nèi)的字元(佔(zhàn)一個(gè)位元組的字元)就顯得非常浪費(fèi)。 JDK1.9 的 String 類別為了節(jié)省記憶體空間,於是使用了佔(zhàn) 8 位,1 個(gè)位元組的 byte 陣列來(lái)存放字串。

而新屬性 coder 的作用是,在計(jì)算字串長(zhǎng)度或使用 indexOf()函數(shù)時(shí),我們需要根據(jù)這個(gè)字段,判斷如何計(jì)算字串長(zhǎng)度。 coder 屬性預(yù)設(shè)有 0 和 1 兩個(gè)值,0 代表 Latin-1(單字節(jié)編碼),1 代表 UTF-16。如果 String 判斷字串只包含了 Latin-1,則 coder 屬性值為 0,反之則為 1。

不可變

查看String類別的程式碼可以發(fā)現(xiàn),String類別被final關(guān)鍵字修飾,因此這個(gè)類別不能被繼承,並且String類別裡面的變數(shù)char 陣列也被final 修飾了,因此String物件不能被修改。

String物件不可變主要有以下幾個(gè)優(yōu)點(diǎn):

第一,保證 String 物件的安全性。假設(shè) String 物件是可變的,那麼 String 物件將可能被惡意修改。

第二,保證 hash 屬性值不會(huì)頻繁變更,確保了唯一性,使得類似 HashMap 容器才能實(shí)現(xiàn)對(duì)應(yīng)的 key-value 快取功能。

第三,可以實(shí)作字串常數(shù)池。

在Java 中,通常有兩種創(chuàng)建字串物件的方式:

第一種是透過(guò)字串常數(shù)的方式創(chuàng)建,如

String str = "abc"。

第二種是字串變數(shù)透過(guò)new 形式的創(chuàng)建,如

String str = new String("abc")。

當(dāng)程式碼中使用第一種方式建立字串物件時(shí),在編譯類別檔案時(shí),」abc」常數(shù)字串將會(huì)放入到常數(shù)結(jié)構(gòu)中,在類別載入時(shí),「abc」將會(huì)在常數(shù)池中建立;然後,str將引用常數(shù)池中的字串物件。這種方式可以減少同一個(gè)值的字串物件的重複創(chuàng)建,節(jié)約記憶體。

String str = new String("abc") 這種方式,首先在編譯類別檔案時(shí),」abc」常數(shù)字串將會(huì)放入到常數(shù)結(jié)構(gòu)中,在類別載入時(shí),「abc」將會(huì)在常數(shù)池中建立;其次,在呼叫new時(shí),JVM 指令將會(huì)呼叫String 的建構(gòu)函數(shù),String 物件中的char 陣列將會(huì)引用常數(shù)池中」abc」字符串的char 數(shù)組,在堆內(nèi)存中創(chuàng)建一個(gè)String 對(duì)象;最後,str 將引用String 對(duì)象,String對(duì)象的引用跟常數(shù)池中”abc”字符串的引用是不一樣的。

物件與引用:物件的內(nèi)容儲(chǔ)存在記憶體中,作業(yè)系統(tǒng)透過(guò)記憶體位址來(lái)找到儲(chǔ)存的內(nèi)容,引用就是指記憶體的位址。

例如:

String str = new String("abc"),變數(shù)str指向的是String物件的儲(chǔ)存位址,也就是說(shuō) str 並不是對(duì)象,而只是一個(gè)物件參考。

字串拼接

#常數(shù)相加##

String?str?=?"ab"?+?"cd"?+?"ef";
查看編譯後的字節(jié)碼

0?ldc?#2?<abcdef>2?astore_13?return

可以發(fā)現(xiàn)編譯器將程式碼最佳化成如下所示

String?str=?"abcdef";

變數(shù)相加##

String?a?=?"ab";String?b?=?"cd";String?c?=?a?+?b;
查看編譯後的字節(jié)碼
?0?ldc?#2?<ab>
?2?astore_1?3?ldc?#3?<cd>
?5?astore_2?6?new?#4?<java/lang/StringBuilder>
?9?dup10?invokespecial?#5?<java/lang/StringBuilder.<init>>13?aload_114?invokevirtual?#6?<java/lang/StringBuilder.append>17?aload_218?invokevirtual?#6?<java/lang/StringBuilder.append>21?invokevirtual?#7?<java/lang/StringBuilder.toString>24?astore_325?return
可以發(fā)現(xiàn),Java在進(jìn)行字串相加的時(shí)候,底層使用的是StringBuilder,程式碼被最佳化成如下所示:

String?c?=?new?StringBuilder().append("ab").append("cd").toString();

String.intern

String?a?=?new?String("abc").intern();String?b?=?new?String("abc").intern();System.out.print(a?==?b);
輸出結(jié)果:
true
在字串

常數(shù)

中,預(yù)設(shè)會(huì)將物件放入常量池。例如:

String a = "123"

在字符串變量中,對(duì)象是會(huì)創(chuàng)建在堆內(nèi)存中,同時(shí)也會(huì)在常量池中創(chuàng)建一個(gè)字符串對(duì)象,String 對(duì)象中的 char 數(shù)組將會(huì)引用常量池中的 char 數(shù)組,并返回堆內(nèi)存對(duì)象引用。例如:String b = new String("abc")

如果調(diào)用 intern 方法,會(huì)去查看字符串常量池中是否有等于該對(duì)象的字符串的引用,如果沒(méi)有,在 JDK1.6 版本中會(huì)復(fù)制堆中的字符串到常量池中,并返回該字符串引用,堆內(nèi)存中原有的字符串由于沒(méi)有引用指向它,將會(huì)通過(guò)垃圾回收器回收。

在 JDK1.7 版本以后,由于常量池已經(jīng)合并到了堆中,所以不會(huì)再?gòu)?fù)制具體字符串了,只是會(huì)把首次遇到的字符串的引用添加到常量池中;如果有,就返回常量池中的字符串引用。

下面開(kāi)始分析上面的代碼塊:

在一開(kāi)始字符串”abc”會(huì)在加載類時(shí),在常量池中創(chuàng)建一個(gè)字符串對(duì)象。

創(chuàng)建 a 變量時(shí),調(diào)用 new Sting() 會(huì)在堆內(nèi)存中創(chuàng)建一個(gè) String 對(duì)象,String 對(duì)象中的 char 數(shù)組將會(huì)引用常量池中字符串。在調(diào)用 intern 方法之后,會(huì)去常量池中查找是否有等于該字符串對(duì)象的引用,有就返回常量池中的字符串引用。

創(chuàng)建 b 變量時(shí),調(diào)用 new Sting() 會(huì)在堆內(nèi)存中創(chuàng)建一個(gè) String 對(duì)象,String 對(duì)象中的 char 數(shù)組將會(huì)引用常量池中字符串。在調(diào)用 intern 方法之后,會(huì)去常量池中查找是否有等于該字符串對(duì)象的引用,有就返回常量池中的字符串引用。

而在堆內(nèi)存中的兩個(gè)String對(duì)象,由于沒(méi)有引用指向它,將會(huì)被垃圾回收。所以 a 和 b 引用的是同一個(gè)對(duì)象。

如果在運(yùn)行時(shí),創(chuàng)建字符串對(duì)象,將會(huì)直接在堆內(nèi)存中創(chuàng)建,不會(huì)在常量池中創(chuàng)建。所以動(dòng)態(tài)創(chuàng)建的字符串對(duì)象,調(diào)用 intern 方法,在 JDK1.6 版本中會(huì)去常量池中創(chuàng)建運(yùn)行時(shí)常量以及返回字符串引用,在 JDK1.7 版本之后,會(huì)將堆中的字符串常量的引用放入到常量池中,當(dāng)其它堆中的字符串對(duì)象通過(guò) intern 方法獲取字符串對(duì)象引用時(shí),則會(huì)去常量池中判斷是否有相同值的字符串的引用,此時(shí)有,則返回該常量池中字符串引用,跟之前的字符串指向同一地址的字符串對(duì)象。

以一張圖來(lái)總結(jié) String 字符串的創(chuàng)建分配內(nèi)存地址情況:

使用 intern 方法需要注意的一點(diǎn)是,一定要結(jié)合實(shí)際場(chǎng)景。因?yàn)槌A砍氐膶?shí)現(xiàn)是類似于一個(gè) HashTable 的實(shí)現(xiàn)方式,HashTable 存儲(chǔ)的數(shù)據(jù)越大,遍歷的時(shí)間復(fù)雜度就會(huì)增加。如果數(shù)據(jù)過(guò)大,會(huì)增加整個(gè)字符串常量池的負(fù)擔(dān)。

判斷字符串是否相等

//?運(yùn)行環(huán)境?JDK1.8String?str1?=?"abc";String?str2?=?new?String("abc");String?str3=?str2.intern();System.out.println(str1==str2);?//?falseSystem.out.println(str2==str3);?//?falseSystem.out.println(str1==str3);?//?true
//?運(yùn)行環(huán)境?JDK1.8String?s1?=?new?String("1")?+?new?String("1");s1.intern();String?s2?=?"11";System.out.println(s1?==?s2);?//?true?,?如果不執(zhí)行1.intern(),則返回false

String s1 = new String("1") + new String("1")會(huì)在堆中組合一個(gè)新的字符串對(duì)象"11",在s1.intern()之后,由于常量池中沒(méi)有該字符串的引用,所以常量池中生成一個(gè)堆中字符串"11"的引用,此時(shí)String s2 = "11"返回的是堆字符串"11"的引用,所以s1==s2。

在JDK1.7版本以及之后的版本運(yùn)行以下代碼,你會(huì)發(fā)現(xiàn)結(jié)果為true,在JDK1.6版本運(yùn)行的結(jié)果卻為false:

String?s1?=?new?String("1")?+?new?String("1");System.out.println(?s1.intern()==s1);

StringBuilder與StringBuffer

由于String的值是不可變的,這就導(dǎo)致每次對(duì)String的操作都會(huì)生成新的String對(duì)象,這樣不僅效率低下,而且大量浪費(fèi)有限的內(nèi)存空間。

和 String 類不同的是,StringBuffer 和 StringBuilder 類的對(duì)象能夠被多次的修改,并且不產(chǎn)生新的對(duì)象。

StringBuilder 類在 Java 5 中被提出,它和 StringBuffer 之間的最大不同在于 StringBuilder 的方法不是線程安全的(不能同步訪問(wèn))。

由于 StringBuilder 相較于 StringBuffer 有速度優(yōu)勢(shì),所以多數(shù)情況下建議使用 StringBuilder 類。然而在應(yīng)用程序要求線程安全的情況下,則必須使用 StringBuffer 類。

以上是洞察 String字串的詳細(xì)內(nèi)容。更多資訊請(qǐng)關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

本網(wǎng)站聲明
本文內(nèi)容由網(wǎng)友自願(yuàn)投稿,版權(quán)歸原作者所有。本站不承擔(dān)相應(yīng)的法律責(zé)任。如發(fā)現(xiàn)涉嫌抄襲或侵權(quán)的內(nèi)容,請(qǐng)聯(lián)絡(luò)admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費(fèi)脫衣圖片

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅(qū)動(dòng)的應(yīng)用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費(fèi)的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費(fèi)的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強(qiáng)大的PHP整合開(kāi)發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺(jué)化網(wǎng)頁(yè)開(kāi)發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級(jí)程式碼編輯軟體(SublimeText3)

熱門(mén)話題

Laravel 教程
1597
29
PHP教程
1488
72