字元串常量池
- 簡介
- JDK版本問題
- 課前準備
-
- 一、兩種建立對象的方式
-
- 1.直接指派字元串
- 2.new String();
- 3.Intern方法的作用
- 4.思考:
- 4.思考解答
-
- 1)建立main方法
簡介
在 JAVA 語言中有8中基本類型和一種比較特殊的類型String。這些類型為了使他們在運作過程中速度更快,更節省記憶體,都提供了一種常量池的概念。常量池就類似一個JAVA系統級别提供的緩存。
8種基本類型的常量池都是系統協調的,String類型的常量池比較特殊。它的主要使用方法有兩種:
- 直接使用雙引号聲明出來的String對象會直接存儲在常量池中。
-
如果不是用雙引号聲明的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™ 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,如果是其他環境,後序測試補充。*