天天看點

jdk8中字元串常量池的使用簡介JDK版本問題課前準備

字元串常量池

  • 簡介
  • JDK版本問題
  • 課前準備
    • 一、兩種建立對象的方式
      • 1.直接指派字元串
      • 2.new String();
    • 3.Intern方法的作用
    • 4.思考:
    • 4.思考解答
      • 1)建立main方法

簡介

在 JAVA 語言中有8中基本類型和一種比較特殊的類型String。這些類型為了使他們在運作過程中速度更快,更節省記憶體,都提供了一種常量池的概念。常量池就類似一個JAVA系統級别提供的緩存。

8種基本類型的常量池都是系統協調的,String類型的常量池比較特殊。它的主要使用方法有兩種:

  1. 直接使用雙引号聲明出來的String對象會直接存儲在常量池中。
  2. 如果不是用雙引号聲明的String對象,可以使用String提供的intern方法。intern

    方法會從字元串常量池中查詢目前字元串是否存在,若不存在就會将目前字元串放入常量池中

JDK版本問題

因為JDK版本的不同,常量池的實作會有不同,這點需要注意。

具體差別,可以查找相關文檔。

本文,主要是基于JDK8的實踐。

課前準備

一、兩種建立對象的方式

注意:1,2,3的前提都是,常量池和記憶體中,都是幹淨的(即 不存在以下例子中的對象,比如不存在例子1中的“nice”這個對象)

1.直接指派字元串

這種方式建立的字元串對象,隻會在常量池中。

于是,建立對象s的時候,JVM會先去常量池中通過 equals(key) 方法,判斷是否有相同的對象?

存在,則直接傳回該對象在常量池中的引用;

不存在,則會在常量池中建立一個新對象,再傳回引用。

2.new String();

這種方式會保證兩塊區域中都有這個對象,沒有就建立,最後傳回記憶體中的對象引用。

步驟大緻如下:

先檢查常量池中是否存在?

不存在,建立一個;再去記憶體中查找,沒有的話建立一個;

存在的話,就直接去記憶體中查找,沒有的話建立一個;

最後,将記憶體中的引用傳回。

3.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();
           

String中的intern方法中看到,這個方法是一個 native 的方法,但注釋寫的非常明了。

" 當調用 intern方法時,如果池已經包含一個等于此String對象的字元串(用equals(oject)方法确定),則傳回池中的字元串。否則,将此String對象添加到池中,并傳回此String對象的引用。"

4.思考:

這種方式中,s2所得到的是哪一塊區域的引用呢??

4.思考解答

1)建立main方法

//例一:new + new = 常量池
 		String s6 = new String("go") + new String("od"); 
        String s7 = s6.intern(); 
        String s8 = "good";
        System.out.println(s6 == s7); 
        System.out.println(s7 == s8);
        System.out.println(s6 == s8);
       	//true
		//true
		//true
           

已知:s8是常量池中的引用(以下簡稱常量池);

可知:在JDK1.8中,通過“+”拼接的兩個new String()對象,最終傳回的是常量池中的引用。

//例二:記憶體+記憶體 = 記憶體
		String s9 = new String("go") ;
        String s10 = new String("od") ;
        String s11 = s9+s10; 
        String s12 = s11.intern();
        String s13 = "good";
        System.out.println(s11 == s12); 
        System.out.println(s11 == s13); 
        System.out.println(s12 == s13);
        //false
		//false
		//true
           

已知:s13是常量池;

可知:s11是引用,s12是常量池。

//例三:記憶體 + 常量池 = 常量池
    	String s9 = new String("go1") ;
        String s11 = s9+ "od"; 
        String s12 = s11.intern();
        String s13 = "go1od";
        System.out.println(s11 == s12); 
        System.out.println(s11 == s13); 
        System.out.println(s12 == s13);
        //true
        //true
        //true
           

已知:s13是常量池;

可知:s11,s12是常量池。

總結: :

在JDK8中,通過 “+” 号拼接方式生成的字元串,傳回的引用與 “+” 兩邊的内容相關。

當“+” 兩邊都是對象(new)時,傳回的是常量池中的引用;

當“+” 兩邊都是引用變量時(s9/s10),傳回的是記憶體中的引用

當“+” 兩邊既有對象又有引用變量時,傳回的是常量池中的引用

*以上資料,均來自JDK8,如果是其他環境,後序測試補充。*
           

繼續閱讀