1.方法intern()为java内部方法,如下

 public native String intern();

native方法为通过jvm进行运行,jdk8中隐藏了该方法的具体处理方法。

2.作用:该方法注释为

“如果常量池中存在当前字符串, 就会直接返回当前字符串. 如果常量池中没有此字符串, 会将此字符串放入常量池中后, 再返回”。


3.测试代码一

public static void main(String[] args) {
		String s1 = new String("1");
		s1.intern();
		String s2 = "1";
	
		System.out.println(s1 == s2);

		String s3 = new String("1") + new String("1");
		s3.intern();
		String s4 = "11";
		
		System.out.println(s3 == s4);
	}

结果:

jdk6环境下:

false false

jdk8环境下:

false true


原因分析:

1)jdk6的虚拟机结构中常量池主要是在Perm中,即内存模型为对象存放到java堆区(heap)中,而常量池主要是在java方法区。属于不同的两个区域。

  字符串的初始化中,new时会创建一个对象放在java堆中,而通过引号创建则会在常量池中创建常量,两个区域是隔绝的,因此即使intern之后比较引用的话也不会是相同的。

2)jdk7之后由于之前Perm的大小只有4M,已经无法满足项目的发展,因此取消了Perm的限制,而是移动到了堆区,jdk8更是取消了Perm区。

  对于上面代码,s1创建的时候,生成了一个对象和一个对象的值,因此s1对应的是对象的引用,s2是对应的常量的引用。

 s3初始化的时候对于“11”来说只有一个对象,当调用intern的时候,由于没有该常量,因此jdk7之后会生成一个指向对象的引用存放到常量中。而当s4初始化之后,s4也直接为常量中的对象的引用,因此引用值比较之后为true。