1. 程式人生 > >String中intern方法的作用

String中intern方法的作用

前言

讀完這篇文章你可以瞭解,String物件在虛擬機器記憶體中的存放,intern的作用,這麼多String物件的建立到底有什麼區別,String 建立的物件有幾個!!

進入正題

先科普幾個知識點

1.常量池存放於方法區中

2.jdk1.6 方法區放在永久代(java堆的一部分),jdk1.7 特別將字串常量池移動到了的堆記憶體中(使用引數-XX:PermSize 和-XX:MaxPermSize指定大小),jdk1.8放在單獨的元空間裡面(-XX:MaxMetaspaceSzie設定大小),和堆相獨立。所以導致string的intern方法因為以上變化在不同版本會有不同表現。

  1. jdk1.6將Hotspot虛擬機器使用永久代來實現方法區,因為方法區的記憶體回收跟堆記憶體回收其實沒什麼區別,這樣實現可以用垃圾收集器來管理這部分記憶體,但這樣容易導致記憶體溢位(達到-XX:MaxPermSize)。
    這裡寫圖片描述

JDK1.6,JDK1.7常量池的存放如下都存放於堆記憶體中
這裡寫圖片描述
JDK1.8常量池的存放如下
這裡寫圖片描述

知道了常量池在記憶體中的存放後,我們需要先了解一下 String str=”abc”;和 String str =new String(“abc”);的區別

1.String str=”abc”;

JDK1.6
(1) 當常量池中不存在”abc”這個字串的引用,在堆記憶體中new一個String物件,複製這個物件加入常量池,返回常量池中的物件。
這裡寫圖片描述

(2) 當常量池中存在”abc”這個字串物件,str指向這個物件的引用;

這裡寫圖片描述

JDK1.7以上
(1) 當常量池中不存在”abc”這個字串的引用,在堆記憶體中new一個新的String物件,將這個物件的引用加入常量池。(跟1.6的區別是常量池不再存放物件,只存放引用。)
(2) 當常量池中存在”abc”這個字串的引用,str指向這個引用;

2.String str =new String(“abc”)則是單純的在堆記憶體中new一個String物件,通過StringBuilder 跟StringBuffer 構建的物件也是一樣

3.intern方法 (返回常量池中該字串的引用)

(1) 當常量池中不存在”abc”這個字串的引用,將這個物件的引用加入常量池,返回這個物件的引用。


(2) 當常量池中存在”abc”這個字串的引用,返回這個物件的引用;

測試程式碼如下

        String str1 = "計算機";
        String str2 = "計算機";
        System.out.println("str1==str2:" + (str1 == str2));

        String str3 = new String("計算機");
        System.out.println("str1==str3:" + (str1 == str3));
        System.out.println("str1==str3.intern():" + (str1 == str3.intern()));
        System.out.println("str2==str3.intern():" + (str2 == str3.intern()));

        String str4 = new String("計算機");
        System.out.println("str3==str4:" + (str3 == str4));
        System.out.println("str3.intern()==str4.intern():" + (str3.intern() == str4.intern()));


        String str5 = new StringBuilder("軟體").append("工程").toString();
        System.out.println("str5.intern() == str5:" + (str5.intern() == str5));

        String str6 = new String(new StringBuilder("物聯網").append("工程").toString());
        System.out.println("str6.intern() == str6:" + (str6.intern() == str6));

        String str7 = new String("物聯網");
        System.out.println("str7.intern() == str7:" + (str7.intern() == str7));

JDK1.8輸出結果如下:

str1==str2:true
str1==str3:false
str1==str3.intern():true
str2==str3.intern():true
str3==str4:false
str3.intern()==str4.intern():true
str5.intern() == str5:true
str6.intern() == str6:true
str7.intern() == str7:false

這裡著重講解一下為什麼str5,str6和str7的結果不一樣,

str7直接用new String(”物聯網”)建立,”物聯網”這字串在一出現就自動建立成物件存放到常量池中,所以常量池裡面存放的是”物聯網”字串的引用,並不是str7建立的物件的引用。

str5是通過StringBuilder構建的 在new StringBuilder(“軟體”).append(“工程”).toString方法執行後,”軟體工程”這個字串物件才第一次出現。執行了intern方法後str5才被放到常量池中,此時str5跟str5.intern是同一個物件。

str6是作為對照組出現,這裡為了確認StringBuilder 在toString方法執行後會不會把最終字串放進常量池。很顯然並沒有,所以str6的intern才會跟str6是同一個物件。同時它也能驗證出str7的new String()方式在初始化的時候就會把”物聯網”字串放進常量池中,同理我們可以得出在str5構建的時候常量池裡面加入了”軟體”,”工程”這兩個字串(可以自己動手去驗證一下!!)。

JDK1.7結果如下

str1==str2:true
str1==str3:false
str1==str3.intern():true
str2==str3.intern():true
str3==str4:false
str3.intern()==str4.intern():true
str5.intern() == str5:true
str6.intern() == str6:true
str7.intern() == str7:false

當然JDK1.6我們也能大致明確,輸出結果會如下

str1==str2:true
str1==str3:false
str1==str3.intern():true
str2==str3.intern():true
str3==str4:false
str3.intern()==str4.intern():true
str5.intern() == str5:false
str6.intern() == str6:false
str7.intern() == str7:false

分析一下jdk1.6中 str5.intern() == str5的結果為什麼為false,這裡可以這麼看在軟體工程這個物件中構建完成之後,常量池裡面其實存放的只有“軟體”,”工程”這兩個字串,而”軟體工程”這個字串是存放於堆記憶體中的。所以JDK1.6執行了intern後會把“軟體工程”複製到常量池中,並返回常量池中的物件。常量池中的”軟體工程”跟堆記憶體中的軟體工程並不是同一個。

因為沒有嘗試過,如果jdk1.6有不一致的地方歡迎大家指點。

總結

1.String物件可能會在堆記憶體中分配一塊空間建立一個String物件,在常量池中建立該物件的複製jdk 1.6(或引用jdk 1.7及以上),也可能直接指向常量池(永久帶)中的引用(例String str=”xxx”)。還有一種可能是直接在堆記憶體中分配一塊空間建立一個String物件(例 String str=new String(xxx))。

2.intern方法可以看成返回常量池中該字串物件的引用。如果沒有該字串物件就把這個物件(或引用)加到常量池。

3.jdk1.6跟jdk1.7以上的區別是當常量池中不存在這個字串,jdk1.6是直接複製物件到常量池,而jdk1.7以上是把物件的引用加入常量池。

4.類似於”abc”這樣的字串,在第一次被使用到(比如String a=”abc”或者String a=new String(“abc”)或者”abc”.equals(xxx))後就會被載入到常量池中去。

5.面試問題:

(1)現在當有人問 String str = new String(“abc”);建立了幾個物件,常量池有abc欄位是1個,常量池沒有”abc”欄位則是2個。
(2)String str=”abc”;建立了幾個物件(如果常量池裡面已經有物件了就是0個。如果沒有,JDK1.6 2個,JDK1.7以上 1個);
(3)new String(“abc”).intern();建立了幾個物件(如果常量池裡面已經有該字串物件了就是1個,如果沒有就是兩個)

以上是關於String中intern的作用和個人對於記憶體的一些理解,希望大家有所收穫,也期待和大家交流。

相關推薦

Stringintern方法作用

前言 讀完這篇文章你可以瞭解,String物件在虛擬機器記憶體中的存放,intern的作用,這麼多String物件的建立到底有什麼區別,String 建立的物件有幾個!! 進入正題 先科普幾個知識點 1.常量池存放於方法區中 2.jdk1.6 方

Java 的Stringintern方法詳解及測試樣例

intern public String intern() 返回字串物件的規範化表示形式。 一個初始時為空的字串池,它由類 String 私有地維護。 當呼叫 intern 方法時,如果池已經包含一個等於此 String 物件的字串(該物件由 equals(Obj

java 創建string對象機制 字符串緩沖池 字符串拼接機制 字符串intern()方法

結果 減少 存在 pub lse ring 方法 機制 引用 字符串常量池:字符串常量池在方法區中 為了優化空間,為了減少在JVM中創建的字符串的數量,字符串類維護了一個字符串池,每當代碼創建字符串常量時,JVM會首先檢查字符串常量池。如果字符串已經存在池中,就返回池中的實

Stringintern方法

intern public String intern() 返回字串物件的規範化表示形式。 一個初始時為空的字串池,它由類 String 私有地維護。 當呼叫 intern 方法時,如果池已經包含一個等於此 String 物件的字串(該物件由 equals(Objec

JavaStringintern方法

常量池 在理解Java中的String之前有一個必須要知道的概念-常量池 在java的class檔案中,有一塊常量集中存放的區域,這塊地方被稱為常量池。常量池中儲存的常量通常包括關於類,方法,介面等中的常量,以及字串常量,如String s = “java”

Stringintern方法的原理分析

一,前言 ​ 昨天簡單整理了JVM記憶體分配和String類常用方法,遇到了String中的intern()方法。本來想一併總結起來,但是intern方法還涉及到JDK版本的問題,內容也相對較多,所以今天就彌補昨天缺失的知識點。 二,String.intern() ​ 先來看下網上流行的關於intern()方

StringhashCode方法的線程安全

str hash 變量 style 重新 turn ++ 如果 成員 class String{   //默認值是0   int hash;   public int hashCode() { //將成員變量hash緩存到局部變量 int

osgEarth的Rex引擎原理分析(二十)osgEarth::TerrainEngineNodesetMap方法作用

目標:(十二)中的問題12 不同於派生類RexTerrainEngineNode中setMap的內容(詳見(十二)),這裡主要完成以下工作: 1、設定地圖圖層_map 2、   建立地形瓦片模型工廠_tileModelFactory,用於建立覆蓋紋理、高程紋理、影像紋理

Stringintern()方法學習總結

一、new String都是在堆上建立字串物件。當呼叫 intern() 方法時,編譯器會將字串新增到常量池中(stringTable維護),並返回指向該常量的引用。 二、通過字面量賦值建立字串(如:String str=”twm”)時,會先在常量池中查詢是否存在相同的字串,若存在,則將棧

String方法

一、String的方法:   1.構造方法:        String()建立了一個空內容的字串的物件。       String(byte[] b)使用一個位元組陣列來構建一個字串    &n

Stringintern()方法 與執行時常量池(方法區)

String的intern()方法 與執行時常量池(方法區) 在你看這篇文章時我假設你已經瞭解jvm記憶體 1.String.intern()是一個Native方法,作用是:如果字串常量池存在字串相等(equals() )的字串物件,就返回此常量池中的String物件。否則將Stri

String常用方法介紹

本章介紹一些字串中的常用方法,直接看程式碼註釋 public class Test1 { public static void main(String[] args) { String str1 = "abcDRef";

Stringintern()方法

由雙引號定義的字串會儲存在字串常量池中,呼叫intern方法,intern 方法會從字串常量池中查詢當前字串是否存在,若不存在就會將當前字串放入常量池中,再返回當前字串。 比較下面字串: String str1 = “a”; String str2 = “b”;

Stringintern()方法詳解

官方API: intern public String intern() 返回字串物件的規範化表示形式。 一個初始時為空的字串池,它由類 String 私有地維護。 當呼叫 intern 方法時,如果池已經包含一個等於此 String 物件的字串(該物件由 equals(Object

String split 方法的效率問題

問:String 中 split 方法使用時有什麼效率問題嗎? 答:String 的 split 分割字串函式我們一般會如下方式使用。 String[] arr = "a,b,c".split(","); 上面程式碼非常簡潔, 也沒什麼問題。不過一旦我們進行如

Java學習筆記 (十三) String究竟建立了幾個物件 以及Stringintern方法

String究竟建立了幾個物件 看程式碼: 例 1、 public static void main(String[] args) { String s3 = "天道酬勤"; String s4 =new

Stringintern方法的使用場景

在講intern方法前,我們先簡單回顧下Java中常量池的分類。 ## 常量池的分類 Java中常量池可以分為**Class常量池、執行時常量池和字串常量池**。 **1. Class檔案常量池** 在Class檔案中除了有類的版本、欄位、方法、介面等描述資訊外,還有一項資訊是常量池(Constant

Stringintern方法使用場景

在講intern方法前,我們先簡單回顧下Java中常量池的分類。 ## 常量池的分類 Java中常量池可以分為**Class常量池、執行時常量池和字串常量池**。 **1. Class檔案常量池** 在Class檔案中除了有類的版本、欄位、方法、介面等描述資訊外,還有一項資訊是常量池(Constant

對於JVM方法區,永久代,元空間以及字符串常量池的遷移和string.intern方法

ase ane 虛擬機 影響 一個 tle 自定義類加載器 機器 img 在Java虛擬機(以下簡稱JVM)中,類包含其對應的元數據,比如類的層級信息,方法數據和方法信息(如字節碼,棧和變量大小),運行時常量池,已確定的符號引用和虛方法表。 在過去(當自定義類加載器使用

HTML5 | Canvas變量作用域與setInterval()方法的影響

通過 value utf 出現 close span arc shadow cli Demo - 隨機繪制圓環 實現思路: 將一個圓環的繪制分成100份,setInterval()方法定義每隔時間n繪制一段新的,每份的開始路徑都是上一次的結束路徑,實現步進繪制。 通