Java String中intern方法怎麼使用
常數池簡介
在 JAVA 語言中有8種基本型別和一種比較特殊的型別String。這些類型為了使他們在運行過程中速度更快,更節省內存,都提供了一種常量池(在方法區)的概念。常量池就類似一個JAVA系統層級提供的快取。 8種基本類型的常數池都是系統協調的,String類型的常數池比較特殊。
String的常數池的主要使用方法有兩種:
直接使用雙引號宣告出來的String物件會直接儲存在常數池中。
如果不是用雙引號宣告的String對象,可以使用String提供的intern方法將其放到常數池。
intern方法簡介(JDK7)
原型:public native String intern();
說明:
從字串常數池中查詢目前字符串是否存在(透過equals判斷)。
如果存在,則傳回常數池中的字串參考。
如果不存在,把這個String物件引用存到常數池,然後回傳這個String物件的引用。
傳回值:都是傳回String變數對應的字串常數池的參考。
範例
package com.example; public class Demo { public static void main(String argv[]) { String s = "test"; System.out.println(s == s.intern()); } }
JDK6及之前:輸出false
JDK7及之後:輸出true
#原則(JDK6與JDK7)
- ##常數池裡的字串的由來
JDK7及以後呼叫String.intern()#若常數池中有,則傳回常數池中這個字串的參考
若常數池中沒有,則拷貝一份對象,放到常數池(永久代)中;返回值是常數池(永久代)中對應字串實例的引用。
程式測試程式1:
若常數池中沒有,則拷貝一份引用,放到常數池(堆)中;(JDK1.7將String常數池從Perm區移動到了Java Heap區)
package org.example.a;
public class Demo {
public static void main(String argv[]) {
String s1 = new String("1");
s1.intern();
String s2 = "1";
System.out.println(s1 == s2);
String s3 = new String("1") + new String("1");
s3.intern();
String s4 = "11";
System.out.println(s3 == s4);
}
}
登入後複製
結果package org.example.a; public class Demo { public static void main(String argv[]) { String s1 = new String("1"); s1.intern(); String s2 = "1"; System.out.println(s1 == s2); String s3 = new String("1") + new String("1"); s3.intern(); String s4 = "11"; System.out.println(s3 == s4); } }
jdk6:false falsejdk7: false true
例程2:
package org.example.a; public class Demo { public static void main(String argv[]) { String s1 = new String("1"); s1.intern(); String s2 = "1"; System.out.println(s1 == s2); String s3 = new String("1") + new String("1"); String s4 = "11"; s3.intern(); System.out.println(s3 == s4); } }
上述程式碼第二部分有個對調。
結果
jdk6:false falsejdk7:false falsejdk8:false false
#程式分析
#下邊圖中:綠色線條代表String 物件的內容指向。紅色線條代表地址指向。 jdk1.6例程1與例程2的分析如上圖所示。首先說一下 jdk6中的情況,在 jdk6中上述的所有打印都是 false 的,因為 jdk6中的常量池是放在 Perm 區中的,Perm區和正常的 JAVA Heap 區域是完全分開的。上面說過如果是使用引號宣告的字串都是會直接在字串常數池中生成,而 new出來的 String 物件是放在 JAVA Heap 區域。所以拿一個 JAVA Heap 區域的物件位址和字串常數池的物件位址來比較肯定是不相同的,即使呼叫String.intern方法也是沒有任何關係的。
jdk1.7在Jdk6 以及先前的版本中,字串的常數池是放在堆的Perm區的,Perm區是一個類別靜態的區域,主要儲存一些加載類別的訊息,常數池,方法片段等內容,預設大小只有4m,一旦常數池中大量使用intern 會產生java.lang.OutOfMemoryError:PermGen space錯誤的。在 jdk7 的版本中,字串常數池已經從Perm區移到正常的Java Heap區域了。為什麼要移動,Perm 區域太小是一個主要原因,當然據消息稱jdk8已經直接取消了Perm區域,而新建立了一個元區域。應該是jdk開發者認為Perm區域已經不適合現在 JAVA的發展了。字串常數池移動到JAVA Heap區域,現在解釋為什麼會有上述的列印結果。
######例程1的分析######################1.String s1 = new String("1"); ## #######分析:這行程式碼產生了2個物件(常數池中的「1」 和JavaHeap 中的字串物件)。 s.intern(); 這一句是 s1 物件去常數池中尋找後發現 “1” 已經在常數池裡了。 ######此時s1指向的是Java Heap中的字串物件。 #########2.String s2 = "1"; ##########分析:這行程式碼產生一個 s2的引用指向常數池中的「1」物件。結果就是 s1 和 s2 的引用位址不同。 #########3.String s3 = new String("1") new String("1");#######分析:这行代码生成了2个对象(字符串常量池中的“1” 和 Java Heap中的 s3 引用指向的对象“11”(中间还有2个匿名的new String("1")我们不讨论它)。
此时s3 是Java Heap中的字符串对象的引用,对象内容是”11″,此时常量池中是没有 “11”对象的。
4.s3.intern();
分析:这行代码将 s3中的"11"字符串放入String 常量池中,因为此时常量池中不存在"11"字符串,因此常规做法是跟 jdk6 图中表示的那样,在常量池中生成一个"11"的对象,关键点是 jdk7 中常量池不在Perm区域,而是在堆中了。常量池中不需再存储一份对象了,可以直接存储堆中的引用。这份引用指向s3引用的对象。 也就是说引用地址是相同的。
此时,s3是Java Heap中的字符串对象的引用,对象内容是”11″,此时常量池中是有 “11”对象,它保存的就是s3引用地址。
5.String s4 = "11";
这行代码”11″是显式声明的,因此会直接去常量池中创建,创建时发现已经有这个对象了。
此时:s4 == 常量池的“11”对象引用 == s3引用对象的引用
例程2的分析
String s1 = new String("1");
s1.intern();
String s2 = "1";
分析:s1.intern();,这一句往后放也不会有什么影响了,因为对象池中在执行第一句代码String s = new String("1");的时候已经生成“1”对象了。下边的s2声明都是直接从常量池中取地址引用的。 s1 和 s2 的引用地址是不会相等的。
String s3 = new String("1") + new String("1");
分析:这行代码生成了2个对象(字符串常量池中的“1” 和 Java Heap中的 s3 引用指向的对象“11”(中间还有2个匿名的new String("1")我们不讨论它)。
此时s3 是Java Heap中的字符串对象的引用,对象内容是”11″,此时常量池中是没有 “11”对象的。
String s4 = "11";
分析:声明 s4 的时候常量池中是不存在“11”对象的,执行完后,s4是常量池里“11“对象的引用。
s3.intern();
分析:此时常量池中“11”对象已经存在了,不会有任何操作,s3仍然是堆中String对象的引用。因此 s3 != s4
应用实例
package org.example.a; import java.util.Random; public class Demo { static final int MAX = 1000 * 10000; static final String[] arr = new String[MAX]; public static void main(String argv[]) { Integer[] DB_DATA = new Integer[10]; Random random = new Random(10 * 10000); for(int i = 0; i < DB_DATA.length; i++){ DB_DATA[i] = random.nextInt(); } long t = System.currentTimeMillis(); for(int i = 0; i < MAX; i++){ //arr[i] = new String(String.valueOf(DB_DATA[i % DB_DATA.length])); arr[i] = new String(String.valueOf(DB_DATA[i % DB_DATA.length])).intern(); } System.out.println((System.currentTimeMillis() -t) + "ms"); System.gc(); } }
上述代码是一个演示代码,其中有两条语句不一样,一条是使用 intern,一条是未使用 intern。
运行的参数是:-Xmx2g -Xms2g -Xmn1500M
不用intern
2160ms
使用intern
826ms
通过上述结果,我们发现不使用 intern 的代码生成了1000w 个字符串,占用了大约640m 空间。 使用了 intern 的代码生成了1345个字符串,占用总空间 133k 左右。其实通过观察程序中只是用到了10个字符串,所以准确计算后应该是正好相差100w 倍。虽然例子有些极端,但确实能准确反应出 intern 使用后产生的巨大空间节省。
细心的同学会发现使用了 intern 方法后时间上有了一些增长。这是因为程序中每次都是用了 new String 后, 然后又进行 intern 操作的耗时时间,这一点如果在内存空间充足的情况下确实是无法避免的,但我们平时使用时,内存空间肯定不是无限大的,不使用 intern占用空间导致 jvm 垃圾回收的时间是要远远大于这点时间的。 毕竟这里使用了1000w次intern 才多出来1秒钟多的时间。
以上是Java String中intern方法怎麼使用的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

Java 8引入了Stream API,提供了一種強大且表達力豐富的處理數據集合的方式。然而,使用Stream時,一個常見問題是:如何從forEach操作中中斷或返回? 傳統循環允許提前中斷或返回,但Stream的forEach方法並不直接支持這種方式。本文將解釋原因,並探討在Stream處理系統中實現提前終止的替代方法。 延伸閱讀: Java Stream API改進 理解Stream forEach forEach方法是一個終端操作,它對Stream中的每個元素執行一個操作。它的設計意圖是處

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP和Python各有優勢,選擇應基於項目需求。 1.PHP適合web開發,語法簡單,執行效率高。 2.Python適用於數據科學和機器學習,語法簡潔,庫豐富。

PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。

PHP和Python各有優勢,適合不同場景。 1.PHP適用於web開發,提供內置web服務器和豐富函數庫。 2.Python適合數據科學和機器學習,語法簡潔且有強大標準庫。選擇時應根據項目需求決定。

PHPhassignificantlyimpactedwebdevelopmentandextendsbeyondit.1)ItpowersmajorplatformslikeWordPressandexcelsindatabaseinteractions.2)PHP'sadaptabilityallowsittoscaleforlargeapplicationsusingframeworkslikeLaravel.3)Beyondweb,PHPisusedincommand-linescrip

膠囊是一種三維幾何圖形,由一個圓柱體和兩端各一個半球體組成。膠囊的體積可以通過將圓柱體的體積和兩端半球體的體積相加來計算。本教程將討論如何使用不同的方法在Java中計算給定膠囊的體積。 膠囊體積公式 膠囊體積的公式如下: 膠囊體積 = 圓柱體體積 兩個半球體體積 其中, r: 半球體的半徑。 h: 圓柱體的高度(不包括半球體)。 例子 1 輸入 半徑 = 5 單位 高度 = 10 單位 輸出 體積 = 1570.8 立方單位 解釋 使用公式計算體積: 體積 = π × r2 × h (4

PHP成為許多網站首選技術棧的原因包括其易用性、強大社區支持和廣泛應用。 1)易於學習和使用,適合初學者。 2)擁有龐大的開發者社區,資源豐富。 3)廣泛應用於WordPress、Drupal等平台。 4)與Web服務器緊密集成,簡化開發部署。
