欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

JVM理解String类和细讲Stringtable(总体的第十一篇)

时间:2023-08-06

前面的文章中已经学习到了类加载子系统,JVM运行时数据区(内存模型),执行引擎的一系列文章,接下来写一篇结合String类和Stringtable的文章

1、String的基本特性


(1)不可变性

测试不可变性

第一种情况

其实s1和s2都指向了字符串常量池中的“abc”。所有为true第二种情况

其实这种情况在我们的常量池中,刚开始他们两个指向的“abc”,这个在常量池是不会改变的,当我们的s1进行修改后,是在常量池中重新造了一个。看另外一种情况

对s2进行修改,同样的也是再制造一个,而不是在原来的基础上修改。另外一种情况:进行替换。【同样的也没有改变】
(2)不存储相同的值

String底层Hashtable结构说明。


如果你在jdk8和之后的版本中,你设置更小的,是报错的。

2、String的内存分配





java8方法区是落实到了元空间,而字符串常量池还是不变的。

3、String的基本操作



当再次加载到相同的内容时,是不会再去加载相同的内容的。


4、字符串的拼接 (1)拼接的一些面试题

第一种情况

编译期优化,就是在编译的时期就认为我们的s1=“abc”。第二种情况

只要拼接的过程有一个是变量,就在我们的堆中,具体的结果时拼接的结果。new了对象就不会相同。另外一个种情况就是intern方法的情况。
(2)拼接的底层原理

当我们有变量的情况下,它的拼接原理是如下。

StringBuilder调用toString方法就约等于去new 了String【看清楚是约等于,一会在后面的intern方法讲为什么是约等于】

【因为我们这个StringBuilder是在我们的JDK1.5的时候提供的,那之前我们的String用什么进行拼接的呢?其实用的StringBuffer来处理的】

当我们是非变量的时候【即常量的方式】

(3)拼接和append效率比较


分析原因1
通过“+”效率低的原因就是我们每次去创建的StringBuilder和String的情况。
通过创建它StringBuilder的一个对象来进行添加,所以它的效率高很多了。

分析原因2
通过“+”,由于创建了较多的对象,而且是用了就不要了,它内存占用是比较严重的,而且如果进行GC的话,花费的时间也是比较多的情况。

改进的空间也是有的
我们的StringBuilder默认创建的数组大小为16,如果我们在开发中确定字符串的长度是不高于某一个值的情况下,那可以直接调用我们StringBuilder的另外一个构造器,直接确定大小。

5、intern()的使用【重关注不同版本的差别】

首先它是去调用的C的方法库。


(1)new String()到底创建了几个对象

new String()首先来看会制造几个对象?

答案是两个(怎么证明,看字节码)原因就是: new了在堆空间中创建了一个,另外一个就是ldc在字符串常量池中创建了一个字面量。
那我们new String(“a”)+ new String(“b”)制造了几个对象呢?

答案是第一:new了StringBuilder第二:new了String(“a”)对象第三:在字符串常量池里面“a”对象四:new String(“b”)对象5:常量池中放了一个“b”如果再细纠的话:调用了toString了,又去new了一个String类对象。


而且发现它在常量池没有生成一个“ab”的常量引用。 (2)intern()的面试题

jdk6执行结果

第一个返回结果时false原因在于,s显然返回的是堆里面的对象,因为你调用了intern()方法的时,你常量池里面已经存在了一个“1”的对象了,所以你返回的是堆空间的对象地址,而另外一个s2则是字符串常量池里面的对象。
第二结果时false原因是
执行了s3的那行代码执行后,在字符串常量池里面不存在“11”,此时调用我们的intern()方法则要在字符串常量池里面生成一个“11”的引用。

jdk7/8执行结果

在jdk7/8后上面个s和s2相比较当然也不用说都知道,肯定是false而下面种情况则是有不同,因为我们在jdk7的将字符串常量池从永久代移动到了堆空间,所以当你调用s3.intern()方法的时候,它仅仅是去堆空间里面找了一下,“11”的这个的对象。

jdk6 vs jdk7/8



(3) 面试题的扩展


(4)intern()练习扩展1

jdk6的时候

在jdk8/7都是如下样子

还有个例子

(6)intern()练习扩展2

都是在jdk8中
如果这样,则会是false
(7)intern()的空间效率测定


调用了我们的intern()方法的情况,它不会去创建重复的字符串对象。

当你开发中发现大量存在的字符串,尤其其中存在很多重复字符串时,使用intern()可以节省内存空间。

结论
6、StringTable的垃圾回收测试(有参数设置)


可以设置这样的参数来测试

7、G1中的String去重操作

去重操作,指的是堆中的对象去重。



Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。