首先判断常量池中是否存在这个字符串,存在则直接返回常量池中的地址。若不存在,先把它放入常量池中,再返回该地址。
比如(”a“+“b”).intern=="ab"永远为true
接下来用一个个例子解释new string() ,”a“, + 的底层原理。
1、字符串s指向常量池中”ab“的引用,因为"a"
和"b"
都是字面量,并且编译器直接优化成s="ab"
String s="a"+"b";
2、字符串s指向堆中”ab“对象,因为a
和b
都是堆对象的引用,a+b本质使用Stringbuilder.append进行拼接。
String a=new String("a");
String a=new String("b");
String s=a+b;
3、字符串s指向常量池中"ab"的引用,因为a
和b
本质是常量,跟上面同理
final String a=new String("a");
final String a=new String("b");
String s=a+b;
面试题
1、对于String s=new String("a")
会创建两个对象?
会创建2个对象,一个字符串常量池中“a”对象,一个是堆中的"a’对象
2、对于String s=new String("a")+new String("b")
又会创建几个对象?
会创建6个对象!
原理:上一题分析可知new String(“a”)产生2个对象,同理new String(“a”)也产生2个对象,由于+号两边只要有变量,就会使用产生一个stringbuilder对象,最终builder转为String调用toString方法,本质是new String(“ab”)再产生一个对象。
会让常量池指向堆的引用,节省空间。而jdk1.6是直接把堆中的对象拷贝一份。
下面再用几个例子加深对intern函数的理解。
@Test
public void test4() {
String s3=new String("a")+new String("a");
s3.intern(); // 常量池中创建aa,并指向堆中的s3
String s4="aa";
System.out.println(s3==s4); // jdk78 true
String s5=new String("b"); // 堆
String s6="b"; // 常量池
String s7=s5.intern(); // 常量池
System.out.println(s5);
System.out.println(s5==s6); // false
System.out.println(s5==s7); // false
System.out.println(s6==s7); // true
}
@Test
public void test3() {
String str1=new String("hello"+"world");
String intern = str1.intern(); // 返回常量池地址,但该地址是指向堆中的str1
String str2="helloworld"; // 返回常量池地址
System.out.println(str1==intern); // false
System.out.println(str2==intern); // true
}
@Test
public void test2() {
String str1=new String("hello"+"world"); // 堆 同时在方法区常量池生成helloworld,都是常量不会使用stringBuilder
String str1_intern=str1.intern(); // 常量池 直接返回常量池中的helloworld,因为上一个语句已将helloworld放入常量池
String str2="hello"+"world"; // 常量池
String word="word";
String str3=new String("hello"+word); // 堆 有一个是变量就是用builder,因为编译时不知道变量的具体值
System.out.println(str1==str2); // false 因为str1指向堆,str2指向常量池
System.out.println(str1==str1_intern); // false str1_intern返回的常量池的地址
System.out.println(str2==str1_intern); // true
System.out.println(str1==str3); // false 两个是不同的普通的堆对象
}
@Test
public void test1(){
String str1="hello"; // 指向常量池
String str2=new String("hello"); // 指向堆中的地址,但实际引用的是堆中的字符串常量池地址
String str3=str2.intern(); // 指向常量池
System.out.println(str1==str2); // false
System.out.println(str1==str3); // true
System.out.println(str2==str3); // false
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)