真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

String字符串的示例分析-創(chuàng)新互聯(lián)

這篇文章主要介紹String字符串的示例分析,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!

創(chuàng)新互聯(lián)主要從事網(wǎng)站設計制作、成都網(wǎng)站設計、網(wǎng)頁設計、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務。立足成都服務河間,十年網(wǎng)站建設經(jīng)驗,價格優(yōu)惠、服務專業(yè),歡迎來電咨詢建站服務:028-86922220

實現(xiàn)原理

在 Java6 以及之前的版本中,String 對象是對 char 數(shù)組進行了封裝實現(xiàn)的對象,主要有四個成員變量:char 數(shù)組、偏移量 offset、字符數(shù)量 count、哈希值 hash。

從 Java7 版本開始到 Java8 版本,String 類中不再有 offset 和 count 兩個變量了。這樣的好處是 String 對象占用的內(nèi)存稍微少了些。

從 Java9 版本開始,將 char[]字段改為了 byte[]字段,又維護了一個新的屬性 coder,它是一個編碼格式的標識。

一個 char 字符占 16 位,2 個字節(jié)。這個情況下,存儲單字節(jié)編碼內(nèi)的字符(占一個字節(jié)的字符)就顯得非常浪費。JDK1.9 的 String 類為了節(jié)約內(nèi)存空間,于是使用了占 8 位,1 個字節(jié)的 byte 數(shù)組來存放字符串。

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

不可變

查看String類的代碼可以發(fā)現(xiàn),String類被final關鍵字修飾,因此這個類不能被繼承,并且String類里面的變量char 數(shù)組也被 final 修飾了,因此String對象不能被修改。

String對象不可變主要有如下幾個優(yōu)點:

第一,保證 String 對象的安全性。假設 String 對象是可變的,那么 String 對象將可能被惡意修改。

第二,保證 hash 屬性值不會頻繁變更,確保了性,使得類似 HashMap 容器才能實現(xiàn)相應的 key-value 緩存功能。

第三,可以實現(xiàn)字符串常量池。

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

第一種是通過字符串常量的方式創(chuàng)建,如String str = "abc"。

第二種是字符串變量通過new 形式的創(chuàng)建,如String str = new String("abc")。

當代碼中使用第一種方式創(chuàng)建字符串對象時,在編譯類文件時,”abc”常量字符串將會放入到常量結(jié)構(gòu)中,在類加載時,“abc”將會在常量池中創(chuàng)建;然后,str將引用常量池中的字符串對象。這種方式可以減少同一個值的字符串對象的重復創(chuàng)建,節(jié)約內(nèi)存。

String str = new String("abc") 這種方式,首先在編譯類文件時,”abc”常量字符串將會放入到常量結(jié)構(gòu)中,在類加載時,“abc”將會在常量池中創(chuàng)建;其次,在調(diào)用new時,JVM 命令將會調(diào)用 String 的構(gòu)造函數(shù),String 對象中的 char 數(shù)組將會引用常量池中”abc”字符串的char 數(shù)組,在堆內(nèi)存中創(chuàng)建一個 String 對象;最后,str 將引用 String 對象,String對象的引用跟常量池中”abc”字符串的引用是不一樣的。

對象與引用:對象的內(nèi)容存儲在內(nèi)存中,操作系統(tǒng)通過內(nèi)存地址來找到存儲的內(nèi)容,引用就是指內(nèi)存的地址。

比如:String str = new String("abc"),變量str指向的是String對象的存儲地址,也就是說 str 并不是對象,而只是一個對象引用。

字符串拼接

常量相加

String str = "ab" + "cd" + "ef";

查看編譯后的字節(jié)碼

0 ldc #2 2 astore_13 return

可以發(fā)現(xiàn)編譯器將代碼優(yōu)化成如下所示

String str= "abcdef";

變量相加

String a = "ab";String b = "cd";String c = a + b;

查看編譯后的字節(jié)碼

 0 ldc #2 
 2 astore_1 3 ldc #3 
 5 astore_2 6 new #4 
 9 dup10 invokespecial #5 >13 aload_114 invokevirtual #6 17 aload_218 invokevirtual #6 21 invokevirtual #7 24 astore_325 return

可以發(fā)現(xiàn),Java在進行字符串相加的時候,底層使用的是StringBuilder,代碼被優(yōu)化成如下所示:

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

在字符串常量中,默認會將對象放入常量池。例如:String a = "123"

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

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

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

下面開始分析上面的代碼塊:

在一開始字符串”abc”會在加載類時,在常量池中創(chuàng)建一個字符串對象。

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

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

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

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

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

String字符串的示例分析

使用 intern 方法需要注意的一點是,一定要結(jié)合實際場景。因為常量池的實現(xiàn)是類似于一個 HashTable 的實現(xiàn)方式,HashTable 存儲的數(shù)據(jù)越大,遍歷的時間復雜度就會增加。如果數(shù)據(jù)過大,會增加整個字符串常量池的負擔。

判斷字符串是否相等

// 運行環(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
// 運行環(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")會在堆中組合一個新的字符串對象"11",在s1.intern()之后,由于常量池中沒有該字符串的引用,所以常量池中生成一個堆中字符串"11"的引用,此時String s2 = "11"返回的是堆字符串"11"的引用,所以s1==s2

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

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

StringBuilder與StringBuffer

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

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

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

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

以上是“String字符串的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對大家有幫助,更多相關知識,歡迎關注創(chuàng)新互聯(lián)行業(yè)資訊頻道!


網(wǎng)頁名稱:String字符串的示例分析-創(chuàng)新互聯(lián)
當前URL:http://weahome.cn/article/codgjs.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部