最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中String字符串常量池和intern方法源碼分析

 更新時間:2023年05月19日 11:20:20   作者:一一哥Sun  
在之前的文章中,小編給大家介紹了String字符串的不可變性及其實現(xiàn)原理,其中給大家提到了字符串常量池的概念,那么什么是常量池,String字符串與常量池有什么關(guān)系,本文給大家嘮嘮字符串常量池及String#intern()方法的作用,需要的朋友可以參考下

一. 常量池簡介

1. 基本概念

常量池是堆中的一塊存儲區(qū)域,用于存儲顯式的String、float、Integer等數(shù)據(jù)。這是一個特殊的共享區(qū)域,開發(fā)時不需要在內(nèi)存中經(jīng)常改變的數(shù)據(jù),都可以放在這里進行共享。JDK 7及其之前的常量池是在方法區(qū)中,從Java8之后,常量池存放到了堆中。

為了讓大家更好地理解常量池的作用,給大家分析一下String字符串的內(nèi)存分配。

2. 實驗案例

我們先來編寫一行代碼,如下所示:

//String對象創(chuàng)建
String s = new String("xyz");

這個代碼很簡單,就一行代碼!那么問題來了,這行代碼中幾個對象的內(nèi)存分配是如何的?接下來就給大家把這段代碼的內(nèi)存分區(qū)繪制一下(本案例開發(fā)環(huán)境是基于JDK8)。

3. 內(nèi)存分配(重點)

String s = new String("xyz"); 這行代碼中,s是String類型的變量,不是對象!‘xyz’是字符串對象,new String("xyz")也是一個對象,那么它們幾個的內(nèi)存劃分在JDK8的環(huán)境中,如下圖所示:

根據(jù)上圖,給大家分析一下上述代碼的內(nèi)存分配情況,如下所示:

當(dāng)JVM在編譯階段加載讀取到“xyz”的時候,首先會檢查堆中的String常量池,也就是常量緩沖區(qū)。檢查是否已經(jīng)有了"xyz"常量對象,如果有,則不會再次創(chuàng)建"xyz"常量對象,并直接返回該字符串的引用地址;如果沒有,則創(chuàng)建一個"xyz"常量對象,并為該對象分配一個內(nèi)存地址002返回;

當(dāng)JVM在運行階段加載讀取到new關(guān)鍵字的時候,JVM會在堆中為其創(chuàng)建一個對象,即new String(),并為其分配內(nèi)存地址001,而堆中這個對象的內(nèi)容是上面"xyz"常量對象的引用地址002,換句話說這個堆中存的就是常量池中"xyz"的引用地址002;

最后,s 是對當(dāng)前堆中001號對象的一個地址引用,s本身不是一個對象,s只是一個String類型的變量而已!

二. intern()方法(重點)

了解了常量池的內(nèi)容之后,接下來請大家再跟著小編來看看String的intern()方法,這個方法很重要,請大家記住哦。

/**
     * Returns a canonical representation for the string object.
     * <p>
     * A pool of strings, initially empty, is maintained privately by the
     * class {@code String}.
     * <p>
     * When the intern method is invoked, if the pool already contains a
     * string equal to this {@code String} object as determined by
     * the {@link #equals(Object)} method, then the string from the pool is
     * returned. Otherwise, this {@code String} object is added to the
     * pool and a reference to this {@code String} object is returned.
     * <p>
     * It follows that for any two strings {@code s} and {@code t},
     * {@code s.intern() == t.intern()} is {@code true}
     * if and only if {@code s.equals(t)} is {@code true}.
     * <p>
     * All literal strings and string-valued constant expressions are
     * interned. String literals are defined in section 3.10.5 of the
     * <cite>The Java&trade; Language Specification</cite>.
     *
     * @return  a string that has the same contents as this string, but is
     *          guaranteed to be from a pool of unique strings.
     */
    public native String intern();

從上面的源碼注釋中我們可以知道,intern()是由C語言實現(xiàn)的native底層方法,用于從String緩存池中獲取一個與該字符串內(nèi)容相同的字符串對象。當(dāng)這個intern()方法被執(zhí)行的時候,如果緩存池中已經(jīng)有這個String內(nèi)容,則直接從這個緩存池中獲取該String內(nèi)容對象;如果緩存池中沒有這個String內(nèi)容對象,則把這個String內(nèi)容對象放到緩存池中,并返回這個字符串對象的引用。 現(xiàn)在我們知道了intern()方法的功能,但是該方法的底層原理是什么樣的呢?接下來給結(jié)合一段代碼案例,給各位詳細(xì)說一下:

//常量池與堆的關(guān)系
String str1="yiyige";
String str2=new String("yiyige");
System.out.println("str1==str2的結(jié)果==> " +(str1==str2));

String str3 = str2.intern();
System.out.println("str1==str3的結(jié)果==> " +(str1==str3));

執(zhí)行結(jié)果如下圖所示:

intern()方法的底層原理如下(重點):

Java專門為String類設(shè)計了一個緩存池intern pool,intern pool是在方法區(qū)中的一塊特殊存儲區(qū)域,當(dāng)我們通過 String str="yiyige" 這樣的方式來構(gòu)造一個新的字符串時,String類會優(yōu)先在緩存池中查找是否已經(jīng)存在內(nèi)容相同的String對象。如果有則直接返回該對象的地址引用,如果沒有就會構(gòu)造一個新的String對象,然后放進緩存池,再返回該字符串的地址引用。因此,即使我們構(gòu)造一萬個String str = "yiyige",但實際上得到的都是同一個地址引用,這樣就避免了很多不必要的空間開銷。注意:intern池不適用new String("yiyige")的構(gòu)造形式!

注意:

因為字符串常量池存放位置發(fā)生了變化,String類對intern()方法也進行了一些修改:

JDK 6 版本中執(zhí)行intern()方法時,首先會判斷字符串常量池中是否存在該字符串字面量,如果不存在則拷貝一份字符串字面量存放到常量池中,最后返回該字符串字面量的唯一引用。如果發(fā)現(xiàn)字符串常量池中已經(jīng)存在,則直接返回該字符串字面量的唯一引用。

JDK 7 以后執(zhí)行intern()方法時,如果發(fā)現(xiàn)字符串常量池中不存在該字符串字面量,則不會再拷貝一份字面量,而是拷貝字面量對應(yīng)堆中的一個地址引用,然后返回這個引用。

現(xiàn)在我們知道了,原來當(dāng)一個String對象被創(chuàng)建時,如果發(fā)現(xiàn)當(dāng)前String對象已經(jīng)存在于String Pool中了,就會返回一個已存在的String對象引用而不會新建一個對象。比如以下代碼只會在常量池中創(chuàng)建一個String對象。

String str1 = "yiyige"; 
String str2 = "yiyige";

創(chuàng)建過程如下圖所示:

如果一個String是可變的,當(dāng)改變了A引用指向的String時,可能就會導(dǎo)致其他的B引用得到錯誤的值,所以Sting就被設(shè)計為不可變的。String底層主要是使用intern緩存池將字符串緩存起來,同時允許把一個String字符串的地址賦值給多個String變量來引用,這樣就可以保證多個變量安全地共享同一個對象。如果Java中的String對象可變的話,一個字符串引用的操作改變了對象的值,那么其他的變量就會受到影響。

三. 結(jié)語

至此,就把字符串相關(guān)的一些常規(guī)原理性知識點,給大家講解梳理完畢了。

到此這篇關(guān)于Java中String字符串常量池和intern方法源碼分析的文章就介紹到這了,更多相關(guān)Java String常量池和intern方法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot實戰(zhàn)之高效使用枚舉參數(shù)(原理篇)案例詳解

    SpringBoot實戰(zhàn)之高效使用枚舉參數(shù)(原理篇)案例詳解

    這篇文章主要介紹了SpringBoot實戰(zhàn)之高效使用枚舉參數(shù)(原理篇)案例詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-09-09
  • 歸并算法之有序數(shù)組合并算法實現(xiàn)

    歸并算法之有序數(shù)組合并算法實現(xiàn)

    這篇文章主要介紹了歸并算法之有序數(shù)組合并算法實現(xiàn)的相關(guān)資料,需要的朋友可以參考下
    2017-07-07
  • java8新特性之接口默認(rèn)方法示例詳解

    java8新特性之接口默認(rèn)方法示例詳解

    這篇文章主要給大家介紹了關(guān)于java8新特性之接口默認(rèn)方法的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用java8具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • Maven生命周期和及插件原理用法詳解

    Maven生命周期和及插件原理用法詳解

    這篇文章主要介紹了Maven生命周期和及插件原理用法詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值的相關(guān)資料
    2020-08-08
  • 深入淺析Mybatis與Hibernate的區(qū)別與用途

    深入淺析Mybatis與Hibernate的區(qū)別與用途

    這篇文章主要介紹了Mybatis與Hibernate的區(qū)別與用途的相關(guān)資料,需要的朋友可以參考下
    2017-10-10
  • 劍指Offer之Java算法習(xí)題精講鏈表與二叉樹專項訓(xùn)練

    劍指Offer之Java算法習(xí)題精講鏈表與二叉樹專項訓(xùn)練

    跟著思路走,之后從簡單題入手,反復(fù)去看,做過之后可能會忘記,之后再做一次,記不住就反復(fù)做,反復(fù)尋求思路和規(guī)律,慢慢積累就會發(fā)現(xiàn)質(zhì)的變化
    2022-03-03
  • 詳解Java之冒泡排序與選擇排序

    詳解Java之冒泡排序與選擇排序

    這篇文章主要為大家介紹了Java之冒泡排序與選擇排序,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2021-12-12
  • 詳解如何給SpringBoot部署的jar包瘦身

    詳解如何給SpringBoot部署的jar包瘦身

    這篇文章主要介紹了如何給SpringBoot部署的jar包瘦身,如今迭代發(fā)布是常有的事情,每次都上傳一個如此龐大的文件,會浪費很多時間,接下來小編就以一個小項目為例,來演示如何給jar包瘦身,需要的朋友可以參考下
    2023-07-07
  • RocetMQ搭建步驟與問題解決之道

    RocetMQ搭建步驟與問題解決之道

    這篇文章主要給大家介紹了關(guān)于RocetMQ搭建步驟與問題解決之道的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • 基于Java實現(xiàn)無向環(huán)和有向環(huán)的檢測

    基于Java實現(xiàn)無向環(huán)和有向環(huán)的檢測

    這篇文章主要介紹了如何在?Java?中實現(xiàn)無向環(huán)和有向環(huán)的檢測,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Java有一定的幫助,需要的可以參考一下
    2022-04-04

最新評論

定兴县| 湖南省| 郎溪县| 龙江县| 乐至县| 乌苏市| 大港区| 宁蒗| 乌审旗| 长宁县| 蛟河市| 德钦县| 泽普县| 江口县| 巴林左旗| 扎赉特旗| 大同市| 乌苏市| 台北市| 陈巴尔虎旗| 留坝县| 沐川县| 额济纳旗| 莱阳市| 屏东市| 贵阳市| 阿拉善右旗| 林芝县| 易门县| 虞城县| 年辖:市辖区| 横山县| 资阳市| 宝坻区| 武平县| 蓬溪县| 巴里| 武平县| 福清市| 大同市| 奈曼旗|