JVM15

it2025-04-25  8

new String(“ab”)到底创建了几个对象

从字节码的角度可以很清楚的知道是两个对象。 第一个就是new关键字创建了一个String对象在堆中,第二个,这个ab字符串对象第一次出现,所以会先在堆中的字符串常量池创建,然后从常量池取出字符串ab (ldc指令是从常量池中获取值的) , 放到堆中String对象的空间中。str 引用指向了String 对象

String s = new String(“a”) + new String(“b”);

通过字节码可以看到,首先因为是 加号左右是引用变量,所以创建了StringBuilder对象,接着就是两个new String()以及常量池中字符串对象的创建 最后StringBuilder的toString方法中是存在new String()操作的, 也就是总共创建 了6个对象。

再看toString方法,发现并没有字符串"ab", 也就是字符串常量池不存在ab

最后也就是new String(“ab”) ,然后str 指向了堆中的这个String 对象

一道面试题

JDK6中,字符串常量池是在永久代。 对于上边代码执行结果是false\false 首先String s = new String(“1”); 在堆中创建一个对象,并且因为常量池此时也没有这个字符串,所以也同时创建了一个 s.inter(); 这步就有点多余,常量池已经存在字符串"1" 了 String s2 = “1”; s2 指向的是字符串常量池中的1 ,而s 指向的是堆中的1,所以返回false

String s3 = new String() + new String(); 这一步相当于String s3 = new String(“11”); 由开始的案例知道,此时在常量池并不存在11 s3.intern();在常量池产生了11 s4 使用上一行产生的11, s3指向堆中11,s4指向常量池11,所以返回false

**JDK7或8 ** 返回结果是:false、true 前半个代码解释一样。 String s3 = new String() + new String(); 这一步相当于String s3 = new String(“11”); 由开始的案例知道,此时在常量池并不存在11 s3.intern(); 此时这一步是关键,它并没有在常量池中创建字符串对象11, JDK7中因为字符串常量池也在堆中,为了节省空间,在常量池中只放了一个s3的引用 String s4 = “11”; 此时s4指向常量池中的引用,而这个引用指向堆中的字符串11 所以s3 和s4都指向了同一个对象,返回true

JDK6中 JDK7、8 拓展: s3 指向堆中的11,但是并没有在字符串常量池放11 s4指向字符串常量池中新创建的字符串对象11 s3调用intern()方法,就会去字符串常量池中检查是否存在这个字符串11,发现存在这个字符串,所以就会返回常量池中这个字符串的地址 所以此时s5和s4都指向常量池中的11 总结 案例1

intern()空间效率测试

字符串的操作,加了intern() 首先是时间上的提升,然后再观察内存的占用,因为在前边的操作中已经在字符串常量池中创建过1-10,所以后边只是一个引用返回,节省了在堆中创建字符串对象的时间和空间

new String(“a”).intern(); 的操作,在字符串常量池中产生a字符串后,堆中的a就失去作用,在以后就会进行GC

对于程序中大量存在的字符串,尤其是其中存在很多重复字符串时,使用intern()可以节省内存空间

StringTable的垃圾回收行为

String.valueOf(j) 底层还是一个new String() 当new String().intern() ,对象创建很多以后,就会出现YGC,回收掉堆中那些没用的字符串对象

G1的String去重操作

hashtable用的很多,所以面试常考

最新回复(0)