返回博主主页

java字符串String的intern()方法,举例说明

 

参考

  1.  new String都是在堆上创建字符串对象。当调用 intern() 方法时,编译器会将字符串添加到常量池中(stringTable维护),并返回指向该常量的引用。
  2. 通过字面量赋值创建字符串(如:String str=”twm”)时,会先在常量池中查找是否存在相同的字符串,若存在,则将栈中的引用直接指向该字符串;若不存在,则在常量池中生成一个字符串,再将栈中的引用指向该字符串。
  3. 常量字符串的“+”操作,编译阶段直接会合成为一个字符串。如string str=”JA”+”VA”,在编译阶段会直接合并成语句String str=”JAVA”,于是会去常量池中查找是否存在”JAVA”,从而进行创建或引用。
  4. 对于final字段,编译期直接进行了常量替换(而对于非final字段则是在运行期进行赋值处理的)。
    final String str1=”ja”;
    final String str2=”va”;
    String str3=str1+str2;
    在编译时,直接替换成了String str3=”ja”+”va”,根据第三条规则,再次替换成String str3=”JAVA”
  5. 常量字符串和变量拼接时(如:String str3=baseStr + “01”;)会调用stringBuilder.append()在堆上创建新的对象。
  6. JDK 1.7后,intern方法还是会先去查询常量池中是否有已经存在,如果存在,则返回常量池中的引用,这一点与之前没有区别,区别在于,如果在常量池找不到对应的字符串,则不会再将字符串拷贝到常量池,而只是在常量池中生成一个对原字符串的引用。简单的说,就是往常量池放的东西变了:原来在常量池中找不到时,复制一个副本放到常量池,1.7后则是将在堆上的地址引用复制到常量池。

例子:

package util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.util.Arrays;
public class Main20210907{
	public static void main(String[] args) {

//		一次
		fun1();
		System.out.println();
		fun2();		
		System.out.println();
		fun3();
		System.out.println();
		fun4(1);
		System.out.println();
		fun5();
	}
	public static void fun1() {
		System.out.println("fun1");
		String s1 = new String("str"); //等价于两句String s0="str";String s1 = new String(s0);第一句作用:常量池中检查,没有,把常量对象"str"放进常量池中;第二句作用:new String必然会在jvm堆中创建了一个实例
		s1.intern();//从字符串常量池中查询当前字符串是否存在,存在不作处理
		String s2 = "str";//在常量池中已有常量"str",s2拿过来
		System.out.println(s1==s2);//所以为false,因为s1为new的新的实例,s2取得常量池中的常量
		System.out.println(s1.intern()==s2);//true
	}
	
	public static void fun2() {
		System.out.println("fun2");
		String s1 = new String("a")+new String("bc");//会把常量"a"和"bc"放进常量池,"abc"不会放进常量池
		s1.intern();//检查常量池是否有字符串"abc",常量池不存在"abc",所以(jdk1.6将"abc"复制到常量池,jdk1.7将"abc"的引用放入常量池)
		/**
		 * JDK 1.7后,intern方法还是会先去查询常量池中是否有已经存在,如果存在,则返回常量池中的引用,这一点与之前没有区别,
		 * 区别在于,如果在常量池找不到对应的字符串,则不会再将字符串拷贝到常量池,而只是在常量池中生成一个对原字符串的引用。
		 * 简单的说,就是往常量池放的东西变了:原来在常量池中找不到时,复制一个副本放到常量池,1.7后则是将在堆上的地址引用复制到常量池。
		 */
		String s2 = "abc";//检查常量池有字符串"abc",返回它的引用
		System.out.println(s1==s2); //true
		System.out.println(s1.intern()==s2);//true
	}
	
	public static void fun3() {
		System.out.println("fun3");
		String s0="def"; //常量池加入"def"
		String s1 = new String("d")+new String("ef"); //常量池加入"d"和"ef"
		s1.intern();//常量池存在"def"(s0),所以不做操作(导致s2与s1不等)
		String s2 = "def";//常量池存在s0="def"
		System.out.println(s1==s2); //false
	}
	public static void fun4(int flag) {
		System.out.println("fun4");
		String h="h", ij="ij";//"h"和"ij"都加入常量池
		String s1 = h+ij;//会调用stringBuilder.append()在堆上创建新的对象”hij“。
//		情况一
		if (flag==1) {
			String s2 = "hij";//检查常量池 不存在,于是加入“hij”
			System.out.println(s1==s2); //false
		}else {
			s1.intern();//检查常量池不存在"hij",所以(jdk1.6将"hij"复制到常量池,jdk1.7将"hij"的引用放入常量池)
			String s2 = "hij";//检查常量池,存在“hij”
			System.out.println(s1==s2); //true
		}

	}
	
	public static void fun5() {
		System.out.println("fun5");
		final String k="k", lm="lm";//"k"和"lm"都加入常量池(final修饰)
		String s1 = k+lm;//直接替换成了String s1=”k”+”lm”,再根据常量字符串的“+”操作,编译阶段直接会合成为一个字符串。所以再次替换为String s1="klm","klm"也纳入常量池;
		String s2 = "klm";//检查常量池,存在“klm”
		System.out.println(s1==s2); //true
	}
}

  

posted @ 2021-09-10 00:07  懒惰的星期六  阅读(370)  评论(0编辑  收藏  举报

Welcome to here

主页