注:intern在jdk1.7之后與之前版本有所改動(dòng),區(qū)別不大文章后面會提嚼酝。
先介紹下jvm內(nèi)存模型:主要是本地方法棧,虛擬機(jī)棧竟坛,堆闽巩,方法區(qū),程序計(jì)數(shù)器(版本不同時(shí)可能方法區(qū)沒了担汤,記不清1.8以后是不是取消了方法區(qū)涎跨,非本文重點(diǎn)以后修正)。
- intern涉及到的主要是堆(存實(shí)例對象) 和 方法區(qū)(存常量數(shù)據(jù))
代碼中用String對象調(diào)用intern時(shí)崭歧,往往是在方法區(qū)中生成一個(gè)與堆中字符串對應(yīng)的字符串常量隅很,今后使用同一個(gè)常量時(shí)減少對堆中對象的訪問,防止該對象的引用在以后指向其他String對象率碾,導(dǎo)致獲取不一致的String值叔营。
對一個(gè)String變量str1而言,使用已有變量str的intern賦值與直接使用"XXX"賦值會由于順序的不一致導(dǎo)致不同的結(jié)果所宰。
不寫了绒尊,發(fā)現(xiàn)怎么都不如別人總結(jié)的好。下面這個(gè)博主寫得很好了仔粥,學(xué)習(xí):
https://blog.csdn.net/soonfly/article/details/70147205
主要是弄清楚intern的使用順序婴谱,判斷常量池中是否已經(jīng)存在String對象的值。
弄清楚 -> 編譯階段:做final String的變量拼接時(shí)躯泰,不需要等到運(yùn)行期谭羔,直接編譯期就拼接完成。做String常量拼接也如是斟冕。final能夠保證代碼在初始化階段安全性口糕,這是jvm的規(guī)定,不會受到指令重排的影響磕蛇。
弄清楚 -> 若對同一個(gè)常量值進(jìn)行多次intern景描,其實(shí)都會指向同一處方法區(qū)的位置
弄清楚 -> 1.7之后,intern使用在直接常量賦值前時(shí)秀撇,方法區(qū)存放的堆中String對象的地址超棺,以后無論多少個(gè)新的String對象使用intern,其返回值都是指向最初的那個(gè)String對象的堆地址呵燕,代碼舉例說明:
public class internTest {
public static void main(String[] args) {
String str2 = new String("str")+new String("01");
str2.intern();
String str3 = new String("str") + new String("01");
String tmp = str3.intern();
System.out.println(str2==tmp);
}
}
結(jié)果輸入:true
結(jié)論:str2和tmp指向同一個(gè)位置的堆中對象棠绘。
分析:這是因?yàn)閟tr2.intern時(shí),已經(jīng)在方法區(qū)生成了"str01"的存儲位置(保存指向str2的堆地址)再扭,str3.intern()判斷方法區(qū)已有該值不能在方法區(qū)新建氧苍,共用該值。