A
String str1= "abc";
String str2= new String("abc");
String str3= str2.intern();
System.out.print(str1==str2);
System.out.print(str2==str3);
System.out.print(str1==str3)
先说结果,上面三个输出结果是false false true
根据jvm的内存划分规则:
在字符串常量中,默认会将对象放入常量池;在字符串变量中,对象是会创建在堆内存中,同时也会在常量池中创建一个字符串对象,赋值到堆内存对象中,并返回堆内存对象引用。
若在每次赋值的时候使用 String 的 intern 方法,如果常量池中有相同值,就会重复使用该对象,返回对象引用,这样一开始在堆中创建的对象就可以被回收掉。
所以:
1.String str1= "abc";这种方式,会在常量池中创建一个值为“abc”的对象,str1引用堆中String对象。
2.String str2 = new String(“abc”) 这种方式,会创建两个对象,首先在常量池中创建值为“abc”的对象;其次,在调用 new 时,JVM 命令将会调用 String 的构造函数,在堆中创建一个String对象,String 对象中的 char 数组将会引用常量池中字符串"abc” ;最后,str2 引用堆中String对象。
3.String str3= str2.intern();这种方式,会在常量池中查找是否有同样值为"abc”的对象,发现已经有了,就直接返回常量池中“abc”对象的引用给str3。
(使用 "abc"常量和使用intern()方法,这两种方式达到的效果其实是一样的。)
所以str1和str3是同一个引用,都是指向常量池中的对象地址,而str2则是指向的在堆中创建的对象地址的引用。
再看下面这个例子
B
String a =new String("abc").intern();
String b = new String("abc").intern();
if(a==b) {
System.out.print("a==b");
}
输出结果是true。
根据jvm规则,
在一开始字符串"abc"会在加载类时,在常量池中创建一个字符串对象。
创建 a 变量时,调用 new Sting() 会在堆内存中创建一个 String 对象,String 对象中的 char 数组将会引用常量池中字符串"abc"。在调用 intern 方法之后,会去常量池中查找是否有等于该字符串对象的引用,有就返回引用。
创建 b 变量时,调用 new Sting() 会在堆内存中创建一个 String 对象,String 对象中的 char 数组将会引用常量池中字符串"abc"。在调用 intern 方法之后,会去常量池中查找是否有等于该字符串对象的引用,有就返回引用。
而这个过程当中在堆内存中创建的两个对象,由于没有引用指向它,将会被垃圾回收。所以 a 和 b 引用的是同一个对象。
网友评论