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

前面的文章中已经学习到了类加载子系统,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去重操作

去重操作,指的是堆中的对象去重。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值