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

Java字符串的intern方法有何奧妙之處

 更新時間:2021年10月09日 16:12:10   作者:吾日三省賈斯汀  
intern() 方法返回字符串對象的規(guī)范化表示形式。它遵循以下規(guī)則:對于任意兩個字符串 s 和 t,當(dāng)且僅當(dāng) s.equals(t) 為 true 時,s.intern() == t.intern() 才為 true

學(xué)習(xí)背景

進入正文學(xué)習(xí)字符串的intern()方法之前,先給下這4個問題,看下自己是否都知道答案?

1、String s1 = “a” + “b”; //創(chuàng)建了幾個對象?
2、String s2 = new String(“ab”); //創(chuàng)建了幾個對象?
3、String s3 = new String(“a”) + new String(“b”); //創(chuàng)建了幾個對象?
4、String s4= new String(“a”) + new String(“a”); s4.intern(); //創(chuàng)建了幾個對象?

如果都清楚,恭喜你,大佬一枚,不用往下學(xué)習(xí)了,哈哈哈!
那如果不太確定或者需要加深自己的理解,建議進入正文一起來了解下吧!
當(dāng)然,也可以拉到最后有答案!

String#intern()示例代碼

先來執(zhí)行一下String調(diào)用intern()方法的一段示例代碼:

public class StringInternTest {
    public static void main(String[] args) {
        String reference1 = new String("a");
        reference1.intern();
        String reference2 = "a";
        System.out.println(reference1 == reference2);

        String reference3 = new String("a") + new String("a");
        reference3.intern();
        String reference4 = "aa";
        System.out.println(reference3 == reference4);
    }
}

JDK1.6 執(zhí)行輸出結(jié)果:

false
false

JDK1.7 執(zhí)行輸出結(jié)果:

false
true

大家可以先思考一下為什么結(jié)果是這樣的?往下會具體介紹!

String##intern()源碼

先來看一下intern()方法的JDK源碼如下:

    /**
     * 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()是一個native本地方法,但是native具體實現(xiàn)源碼已經(jīng)被隱藏了,這是一個歷史故事了,SUN公司在JDK7開發(fā)期間,由于技術(shù)競爭和商業(yè)競爭陷入泥潭,無力再投入精力繼續(xù)研發(fā)JDK,Oracle半路殺出直接收購Sun公司,Oracle接管JDK的研發(fā)后,發(fā)版了自己的Oracle JDK,Oracle的native底層等很多源碼就被隱藏了,不過Oracle官方也聲明OpenJDK和Oracle JDK7及以后版本,源碼幾乎是一模一樣的,想要了解native底層源碼具體實現(xiàn)過程,可以下載開源的OpenJDK的源碼進行查看。

OpenJDK官網(wǎng):https://hg.openjdk.java.net/
GitHub也開源啦:https://github.com/openjdk/jdk

例如String對應(yīng)的OpenJDK底層源碼主入口:jdk7\jdk\src\share\native\java\lang\String.c

Java_java_lang_String_intern(JNIEnv *env, jobject this)
{
    return JVM_InternString(env, this);
}

native底層方法的實現(xiàn),需要掌握C和C++的語法,學(xué)習(xí)門檻要求比較高,這里不是我們要學(xué)習(xí)的重點,不做具體介紹。

String#intern()方法作用

前面JDK源碼intern()方法的英文注釋已經(jīng)說明了intern()方法的有具體用途了,網(wǎng)上也有很多說明,不過這里我以個人的理解以及話術(shù)簡單概括下intern()方法的作用如下:

(1)只要調(diào)用String對象的intern(),都會去找到字符串常量池,然后判斷String對象的字符串內(nèi)容是否已經(jīng)存在常量池中,不存在,則往字符串常量池中創(chuàng)建該字符串內(nèi)容的對象(JDK6及之前)或創(chuàng)建新的引用并指向堆區(qū)已有對象地址(JDK7之后),存在則直接返回。

(2)JDK7時,字符串常量池從永久代脫離,遷移到堆區(qū)中,相比于JDK6,變化不只是字符串常量池遷移到堆區(qū)而已,另一個變化就是調(diào)用字符串對象的intern()方法,如果字符串常量池中不存在該字符串內(nèi)容的對象,則不會再像JDK6直接往字符串常量池中創(chuàng)建該字符串內(nèi)容的對象,而是創(chuàng)建一個新的引用并指向堆區(qū)已有對象地址,實現(xiàn)字符串常量池和堆區(qū)字符串共用的目的,效率更高。

JDK6 String#intern()執(zhí)行說明

一張圖介紹前面示例代碼JDK6執(zhí)行過程如下:

在這里插入圖片描述

/**
 * JDK6 String#intern()執(zhí)行說明
 */
public class StringInternTest {
    public static void main(String[] args) {
        //Step6.1
        //創(chuàng)建了2個對象,分別是堆區(qū)的String對象和字符串常量池中的"a"對象,reference1引用指向在堆區(qū)中的對象地址
        String reference1 = new String("a");
        //Step6.2
        //判斷字符串常量池,是否該字符串"a",此前,池中已經(jīng)有該對象了,因此會返回池中的對象地址的引用
        reference1.intern();
        //Step6.3
        //字符串常量池中已存在字符串"a",因此reference2引用直接指向?qū)ο笤谧址A砍刂械牡刂?
        String reference2 = "a";
        //reference1指向?qū)ο蟮刂肥窃诙褏^(qū),reference2指向?qū)ο蟮刂肥窃谟谰么某A砍兀@然不可能一樣
        System.out.println(reference1 == reference2);

        //Step6.4
        //創(chuàng)建了2個對象,分別是在堆區(qū)的String對象(內(nèi)容是"aa")和字符串常量池中的"a"對象
        //reference3引用指向?qū)ο笤诙褏^(qū)中的地址,這過程還會在堆區(qū)創(chuàng)建了兩個無引用的"a"對象,這里不做討論
        String reference3 = new String("a") + new String("a");
        //Step6.5
        //判斷永久代中的字符串常量池,是否存在該字符串"aa",這里是首次出現(xiàn),因此直接將字符串拷貝并放到池中
        reference3.intern();
        //Step6.6
        //池中已存在該字符串,reference2引用直接指向?qū)ο笤谟谰么址A砍刂械牡刂?
        String reference4 = "aa";
        //同樣,reference3指向堆區(qū)地址,reference4指向永久代常量池中的地址,顯然不可能一樣
        System.out.println(reference3 == reference4);
    }
}

JDK7 String#intern()執(zhí)行說明

一張圖介紹前面示例代碼JDK7執(zhí)行過程如下:

在這里插入圖片描述

/**
 * JDK1.7 String#intern()執(zhí)行說明
 **/
public class StringInternTest {
    public static void main(String[] args) {
        //Step7.1
        //創(chuàng)建了2個對象,分別是堆區(qū)的String對象和字符串常量池中的"a"對象,reference1引用指向在堆區(qū)中的對象地址
        String reference1 = new String("a");
        //Step7.2
        //判斷字符串常量池,是否該字符串"a",此前,池中已經(jīng)有該對象了,因此會返回池中的對象地址的引用
        reference1.intern();
        //Step7.3
        //字符串常量池中已存在字符串"a",因此reference2引用直接指向?qū)ο笤谧址A砍刂械牡刂?
        String reference2 = "a";
        //reference1指向?qū)ο蟮刂肥窃诙褏^(qū),reference2指向?qū)ο蟮刂肥窃诙褏^(qū)的字符串常量池,引用指向的對象地址不一樣
        System.out.println( reference1 == reference2);

        //Step7.4
        //創(chuàng)建了2個對象,分別是在堆區(qū)的String對象(內(nèi)容是"aa")和字符串常量池中的"a"對象(注意并不會創(chuàng)建"aa"對象)
        //reference3引用指向?qū)ο笤诙褏^(qū)中的地址,這過程還會在堆區(qū)創(chuàng)建了兩個無引用的"a"對象,這里不做討論
        String reference3 = new String("a") + new String("a");
        //Step7.5
        //判斷堆區(qū)的字符串常量池中,是否存在該字符串"aa",顯然這里是首次出現(xiàn)
        //但并不像JDK6會新建對象"aa"存儲,而是存儲指向堆區(qū)已有對象地址的一個新引用
        reference3.intern();
        //Step7.6
        //指向池中已有該字符串的新引用,reference4引用直接指向字符串常量池中的這個新引用,新引用則指向堆區(qū)已有對象地址
        String reference4 = "aa";
        //reference4指向新引用,而新引用則指向堆區(qū)已有對象地址,跟reference3引用直接指向的對象地址是同一個
        System.out.println(reference3 == reference4);
    }

經(jīng)典面試問題之創(chuàng)建了幾個對象?

在實際的Java面試當(dāng)中,經(jīng)常會被問到字符串創(chuàng)建了幾個對象的問題,主要是考察學(xué)習(xí)者對于對象的實例化以及字符串常量池在JVM結(jié)構(gòu)體系中是如何運行的,個人覺得比較常見問題,無法就是如下幾個:

1、最簡單的比如:String s1 = “a” + “b”;創(chuàng)建了幾個對象?

答:最多1個,多個字符串常量相加會被編譯器優(yōu)化為一個字符串常量即"ab",如果字符串常量池不存在,則創(chuàng)建該對象。

2、相對簡單的比如:String s1 = new String(“ab”);創(chuàng)建了幾個對象?

答:1個或2個,使用new實例化對象,必然會在堆區(qū)創(chuàng)建一個對象,另外一個就是如果在字符串常量池中不存在"ab"這個對象,則會創(chuàng)建這個"ab"常量對象。

3、稍微難一點的比如:String s2 = new String(“a”) + new String(“b”);創(chuàng)建了幾個對象?

答:至少4個,最多6個
堆區(qū)的1個new StringBuilder()和2個new String()
還有1個是StringBuilder()的toString()方法底層實現(xiàn)是new String(value, 0, count)
另外2個即"a"、"b"可能會在常量池新建對象
有的同學(xué)可能會有疑問,那這個toString過程"ab"字符串不會在常量池中也創(chuàng)建嗎?
答案是,不會,最后StringBuilder的toString() 的調(diào)用,底層new String(value, 0, count) 并不會在字符串常量池中去創(chuàng)建"ab"對象。
兩個new String相加會被優(yōu)化為StringBuilder,可以通過javac和javap查看匯編指令如下:
javac InternTest.java
javap -c InternTest

public class com.justin.java.lang.InternTest {
  public com.justin.java.lang.InternTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class java/lang/StringBuilder
       3: dup
       4: invokespecial #3                  // Method java/lang/StringBuilder."<init>":()V
       7: new           #4                  // class java/lang/String
      10: dup
      11: ldc           #5                  // String a
      13: invokespecial #6                  // Method java/lang/String."<init>":(Ljava/lang/String;)V
      16: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      19: new           #4                  // class java/lang/String
      22: dup
      23: ldc           #8                  // String b
      25: invokespecial #6                  // Method java/lang/String."<init>":(Ljava/lang/String;)V
      28: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      31: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      34: astore_1
      35: return
}

最難的無非就是再調(diào)用intern()方法,比如:
String s3= new String(“a”) + new String(“b”);
s3.intern();創(chuàng)建了幾個對象?

答:最少4個,最多7個
1個new StringBuilder()和2個new String
還有1個是StringBuilder()的toString()方法底層實現(xiàn)是new String(value, 0, count)
另外"a"、“b"可能會在常量池新建對象
最后調(diào)用intern()方法時,會去字符串常量池,判斷"ab"是否存在,不存在,JDK6時會創(chuàng)建"ab” 1個對象,JDK7則只創(chuàng)建"ab"的引用并指向堆區(qū)內(nèi)容為"ab"的StringBuilder對象地址。

到此這篇關(guān)于Java字符串的intern方法有何奧妙之處的文章就介紹到這了,更多相關(guān)Java intern方法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 解決springboot與springcloud版本兼容問題(附版本兼容表)

    解決springboot與springcloud版本兼容問題(附版本兼容表)

    在基于spring boot搭建spring cloud時,創(chuàng)建eureka后啟動服務(wù)發(fā)生報錯,本文給大家介紹了解決springboot與springcloud版本兼容問題的幾種方案,需要的朋友可以參考下
    2024-02-02
  • Java多線程工具CompletableFuture詳解

    Java多線程工具CompletableFuture詳解

    這篇文章主要介紹了Java多線程工具CompletableFuture詳解,CompletableFuture?是?java?1.8?追加的新特性,通俗的話來說,是一個函數(shù)式的,用于控制多任務(wù)同步、異步組合操作的工具,需要的朋友可以參考下
    2024-01-01
  • Java微信退款開發(fā)

    Java微信退款開發(fā)

    這篇文章主要為大家詳細介紹了Java微信退款開發(fā)的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-09-09
  • java并發(fā)等待條件的實現(xiàn)原理詳解

    java并發(fā)等待條件的實現(xiàn)原理詳解

    這篇文章主要介紹了java并發(fā)等待條件的實現(xiàn)原理詳解,還是比較不錯的,這里分享給大家,供需要的朋友參考。
    2017-11-11
  • SpringBoot進行數(shù)據(jù)加密和解密的詳細指南

    SpringBoot進行數(shù)據(jù)加密和解密的詳細指南

    對稱加密算法使用相同的密鑰進行加密和解密,其主要優(yōu)點包括速度快和實現(xiàn)簡單,常見的對稱加密算法有 AES、DES 等,本文將以 AES 為例,展示如何在 Spring Boot 項目中進行數(shù)據(jù)加密和解密,需要的朋友可以參考下
    2024-11-11
  • Java的Struts框架簡介與環(huán)境配置教程

    Java的Struts框架簡介與環(huán)境配置教程

    這篇文章主要介紹了Java的Struts框架與其環(huán)境配置教程,Struts框架是Java注明的SSH三大web開發(fā)框架之一,需要的朋友可以參考下
    2015-11-11
  • Java上傳視頻實例代碼

    Java上傳視頻實例代碼

    本文通過實例代碼給大家講解了java上傳視頻功能,代碼分為頁面前臺和后臺,工具類,具體實例代碼大家通過本文學(xué)習(xí)吧
    2018-01-01
  • Java 安全模型,你了解了嗎

    Java 安全模型,你了解了嗎

    這篇文章主要介紹了Java 安全模型。Java的安全模型是其多個重要結(jié)構(gòu)特點之一,它使Java成為適用于網(wǎng)絡(luò)環(huán)境的技術(shù)。Java安全模型側(cè)重于保護終端用戶免受從網(wǎng)絡(luò)下載的、來自不可靠來源的、惡意程序(以及善意程序中的bug)的侵犯。,需要的朋友可以參考下
    2019-06-06
  • Java?深入學(xué)習(xí)static關(guān)鍵字和靜態(tài)屬性及方法

    Java?深入學(xué)習(xí)static關(guān)鍵字和靜態(tài)屬性及方法

    這篇文章主要介紹了Java?深入學(xué)習(xí)static關(guān)鍵字和靜態(tài)屬性及方法,文章通過圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-09-09
  • 深入解析Java類加載的案例與實戰(zhàn)教程

    深入解析Java類加載的案例與實戰(zhàn)教程

    本篇文章主要介紹Tomcat類加載器架構(gòu),以及基于類加載和字節(jié)碼相關(guān)知識,去分析動態(tài)代理的原理,對Java類加載相關(guān)知識感興趣的朋友一起看看吧
    2022-05-05

最新評論

蕉岭县| 邹城市| 马关县| 杭州市| 金湖县| 南昌市| 高陵县| 孟连| 蛟河市| 宁化县| 阿克苏市| 楚雄市| 内丘县| 辽阳县| 房产| 台州市| 巴彦县| 会宁县| 聊城市| 镇赉县| 弋阳县| 静海县| 清镇市| 额尔古纳市| 阳西县| 重庆市| 苍南县| 沾益县| 水富县| 忻城县| 商洛市| 成安县| 青海省| 家居| 霍州市| 如东县| 武宣县| 丹阳市| 乌什县| 曲水县| 岑巩县|