【JVM】String细节

String 细节

JDK 8 以前内部定义了 final char[] value储存字符数据

JDK 9 使用 byte[]储存

不可变性

String:代表不可变的字符序列。简称:不可变性。

  • 当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值。

  • 当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值, 不能使用原有的value进行赋值。

  • 当调用String的replace ()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值

String s1 = "abc";
String s2 = "abc";

sout(s1 == s2);
// true
// 字面量定义方式:字符储存在堆的常量池中,s1, s2 指向同一个地址

s2 += "def";
// s1: abc   s2 : abcdef

String 的基本特性

字符串常量池中是不会存储相同内容的字符串的。

  • String的String Pool是一个固定大小的Hashtable,默认值大小长度是1009。如果放进String Pool的String非常多, 就会造成Hash冲突严重,从而导致链表会很长,而链表长了后直接导致调用 String. intern 时性能会大幅下降。

  • 使用-XX: StringTableSi ze可设置StringTable的长度

  • 在jdk6中StringTable是固定的,就是1009的长度,所以如果常量池中的字符串过多就会导致效率下降很快。StringTablesize设置没有 要求

  • 在jdk7中,StringTable的长 度默认值是60013,1009是 可设置的最小值。

String 拼接

拼接有变量时,会使用 StringBuilder操作:append

sb.append 效率高于字符串的拼接,后者每次拼接会新建 sb , 前者只有一个 sb;

sb.append 存在数组扩容,拷贝原来的数据进入新的数组,可以初始化时直接大容量数组

intern()

从字符串常量池中查询字符串是否存在,若不存在则将字符串放进常量池,返回地址。

String s1 = new String("ab");
// 共 2 个对象:
// 1. new 关键字在堆空间创建的 2. 字符串常量池中的对象,字节码: ldc
 0 new #2 <java/lang/String>
 3 dup
 4 ldc #3 <ab>
 6 invokespecial #4 <java/lang/String.<init>>
 9 astore_1
10 return
String s2 = new String("a") + new String("b");
// 共 6 对象
1 new StringBuilder()
2 new String("a")
3 常量池中的 a
4 new String("b")
5 常量池中的 b
6 sb 中的 new string("ab") (没有在字符串常量池中创建"ab")

题目

		String s1 = new String("1");
        s1.intern(); // 字符串常量池已经存在"1"
        String s2 = "1";
        System.out.println(s1 == s2);

        String s3 = new String("1") + new String("1"); 
		// s3变量的地址是 new String("11")
		// 此时字符串常量池中 没有 "11"
        s3.intern();
		// 在字符串常量池中创建字符"11"
		// JDK 6 : 新的对象, 有新的地址
		// JDK 7 : 常量并未创建新对象, 而是创建指向堆空间中  new String("11") 的地址
        String s4 = "11";
        System.out.println(s3 == s4);

JDK 6 : false false

image-20200516143433103

JDK 7/8 : false true

image-20200516143341093

G1 的 String去重

  • 当垃圾收集器工作的时候,会访问堆上存活的对象。对每个访问的对象都会检查是否是候选的要去重的String对象。
  • 如果是,把这个对象的一个引用插入到队列中等待后续的处理。-一个去重的线程在后台运行,处理这个队列。处理队列的一个元素意味着从队列删除这个元素,然后尝试去重它引用的String对象。
  • 使用一个hashtable来记录所有的被String对象使用的不重复的char数组。
  • 当去重的时候,会查这个hashtable,来看堆上是否已经存在一个一模一样的char数组。
  • 如果存在,string对象会被调整引用那个数组,释放对原来的数组的引用,最终会被垃圾收集器回收掉
  • 如果查找失败,char数组会被插入到hashtable,这样以后的时候就可以共享这个数组了。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值