搜尋
首頁JavaJava基礎洞察 String字串
洞察 String字串Dec 28, 2020 pm 05:27 PM

java基礎教學欄位介紹洞察String字串

洞察 String字串

#推薦(免費):java基礎教學

#實作原理

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

從 Java7 版本開始到 Java8 版本,String 類別中不再有 offset 和 count 兩個變數了。這樣的好處是 String 物件佔用的記憶體稍微少了些。

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

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

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

不可變

查看String類別的程式碼可以發現,String類別被final關鍵字修飾,因此這個類別不能被繼承,並且String類別裡面的變數char 陣列也被final 修飾了,因此String物件不能被修改。

String物件不可變主要有以下幾個優點:

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

第二,保證 hash 屬性值不會頻繁變更,確保了唯一性,使得類似 HashMap 容器才能實現對應的 key-value 快取功能。

第三,可以實作字串常數池。

在Java 中,通常有兩種創建字串物件的方式:

第一種是透過字串常數的方式創建,如

String str = "abc"

第二種是字串變數透過new 形式的創建,如

String str = new String("abc")

當程式碼中使用第一種方式建立字串物件時,在編譯類別檔案時,」abc」常數字串將會放入到常數結構中,在類別載入時,「abc」將會在常數池中建立;然後,str將引用常數池中的字串物件。這種方式可以減少同一個值的字串物件的重複創建,節約記憶體。

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

物件與引用:物件的內容儲存在記憶體中,作業系統透過記憶體位址來找到儲存的內容,引用就是指記憶體的位址。

例如:

String str = new String("abc"),變數str指向的是String物件的儲存位址,也就是說 str 並不是對象,而只是一個物件參考。

字串拼接

#常數相加##

String str = "ab" + "cd" + "ef";
查看編譯後的字節碼

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

可以發現編譯器將程式碼最佳化成如下所示

String str= "abcdef";

變數相加##

String a = "ab";String b = "cd";String c = a + b;
查看編譯後的字節碼
 0 ldc #2 <ab>
 2 astore_1 3 ldc #3 <cd>
 5 astore_2 6 new #4 <java>
 9 dup10 invokespecial #5 <java>>13 aload_114 invokevirtual #6 <java>17 aload_218 invokevirtual #6 <java>21 invokevirtual #7 <java>24 astore_325 return</java></java></java></java></java></cd></ab>
可以發現,Java在進行字串相加的時候,底層使用的是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);
輸出結果:
true
在字串

常數

中,預設會將物件放入常量池。例如:

String a = "123"

在字符串变量中,对象是会创建在堆内存中,同时也会在常量池中创建一个字符串对象,String 对象中的 char 数组将会引用常量池中的 char 数组,并返回堆内存对象引用。例如:String b = new String("abc")

如果调用 intern 方法,会去查看字符串常量池中是否有等于该对象的字符串的引用,如果没有,在 JDK1.6 版本中会复制堆中的字符串到常量池中,并返回该字符串引用,堆内存中原有的字符串由于没有引用指向它,将会通过垃圾回收器回收。

在 JDK1.7 版本以后,由于常量池已经合并到了堆中,所以不会再复制具体字符串了,只是会把首次遇到的字符串的引用添加到常量池中;如果有,就返回常量池中的字符串引用。

下面开始分析上面的代码块:

在一开始字符串”abc”会在加载类时,在常量池中创建一个字符串对象。

创建 a 变量时,调用 new Sting() 会在堆内存中创建一个 String 对象,String 对象中的 char 数组将会引用常量池中字符串。在调用 intern 方法之后,会去常量池中查找是否有等于该字符串对象的引用,有就返回常量池中的字符串引用。

创建 b 变量时,调用 new Sting() 会在堆内存中创建一个 String 对象,String 对象中的 char 数组将会引用常量池中字符串。在调用 intern 方法之后,会去常量池中查找是否有等于该字符串对象的引用,有就返回常量池中的字符串引用。

而在堆内存中的两个String对象,由于没有引用指向它,将会被垃圾回收。所以 a 和 b 引用的是同一个对象。

如果在运行时,创建字符串对象,将会直接在堆内存中创建,不会在常量池中创建。所以动态创建的字符串对象,调用 intern 方法,在 JDK1.6 版本中会去常量池中创建运行时常量以及返回字符串引用,在 JDK1.7 版本之后,会将堆中的字符串常量的引用放入到常量池中,当其它堆中的字符串对象通过 intern 方法获取字符串对象引用时,则会去常量池中判断是否有相同值的字符串的引用,此时有,则返回该常量池中字符串引用,跟之前的字符串指向同一地址的字符串对象。

以一张图来总结 String 字符串的创建分配内存地址情况:

使用 intern 方法需要注意的一点是,一定要结合实际场景。因为常量池的实现是类似于一个 HashTable 的实现方式,HashTable 存储的数据越大,遍历的时间复杂度就会增加。如果数据过大,会增加整个字符串常量池的负担。

判断字符串是否相等

// 运行环境 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
// 运行环境 JDK1.8String s1 = new String("1") + new String("1");s1.intern();String s2 = "11";System.out.println(s1 == s2); // true , 如果不执行1.intern(),则返回false

String s1 = new String("1") + new String("1")会在堆中组合一个新的字符串对象"11",在s1.intern()之后,由于常量池中没有该字符串的引用,所以常量池中生成一个堆中字符串"11"的引用,此时String s2 = "11"返回的是堆字符串"11"的引用,所以s1==s2

在JDK1.7版本以及之后的版本运行以下代码,你会发现结果为true,在JDK1.6版本运行的结果却为false:

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

StringBuilder与StringBuffer

由于String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,这样不仅效率低下,而且大量浪费有限的内存空间。

和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的对象

StringBuilder 类在 Java 5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。

由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。

以上是洞察 String字串的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:learnku。如有侵權,請聯絡admin@php.cn刪除
如何使用Java的Nashorn Engine用JavaScript腳本?如何使用Java的Nashorn Engine用JavaScript腳本?Mar 14, 2025 pm 05:00 PM

Java的Nashorn Engine可以在Java應用程序中啟用JavaScript腳本。關鍵步驟包括設置Nashorn,管理腳本和優化性能。主要問題涉及安全性,內存管理和未來兼容性

如何使用Java的枚舉來表示固定的值集?如何使用Java的枚舉來表示固定的值集?Mar 14, 2025 pm 04:57 PM

Java枚舉代表固定的值集,通過自定義方法和構造函數提供類型安全性,可讀性和其他功能。它們增強了代碼組織,可用於開關語句中以進行有效的價值處理。

如何使用Java的Try-with-Resources語句進行自動資源管理?如何使用Java的Try-with-Resources語句進行自動資源管理?Mar 14, 2025 pm 04:59 PM

Java的Try-with-Resources通過自動關閉文件流或數據庫連接等資源來簡化資源管理,從而提高代碼可讀性和可維護性。

什麼是Java虛擬機(JVM),它在內部如何工作?什麼是Java虛擬機(JVM),它在內部如何工作?Mar 14, 2025 pm 05:05 PM

本文討論了Java虛擬機(JVM),詳細介紹了其在不同平台運行Java程序中的作用。它說明了JVM的內部流程,密鑰組件,內存管理,垃圾收集和性能Optimizatio

Java中有哪些不同的垃圾收集算法(串行,並行,CMS,G1,ZGC)?Java中有哪些不同的垃圾收集算法(串行,並行,CMS,G1,ZGC)?Mar 14, 2025 pm 05:06 PM

本文討論了各種Java垃圾收集算法(串行,並行,CMS,G1,ZGC),它們的性能影響和適合大量堆的應用。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
2 週前By尊渡假赌尊渡假赌尊渡假赌
倉庫:如何復興隊友
4 週前By尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒險:如何獲得巨型種子
4 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

將Eclipse與SAP NetWeaver應用伺服器整合。

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具