JVM之String字符串

今天学习了下字符串

字符串常量池

字符串常量池底层是用StringTable做的,而StringTable是做HashTable做的。在堆区
Hashtable的实现原理跟HashMap差不多,都是数组加链表。

java中的字符串在jvm中是如何存储的?

key生成策略

源码
hashValue = hash_string(name, len);
index = hash_to_index(hashValue);
1.根据字符串和字符串的长度计算出hashValue
2.再根据HashValue计算出index,index就是key

value

HashtableEntry<oop, mtSymbol>* entry = new_entry(hashValue, string());
将String的实例instanceOopDesc封装成HashtableEntry

char数组

在之前的文章中也说过,java存储数组是用两种类型:
TypeArrayKlass:存储基本数据类型数组
ObjArrayKlass:存储引用类型数组
我们创建String对象的时候也会生成一个char数组

public static void main(String[] args) {
    char[] arr = new char[]{'1', '2'};

    while (true);
}

这个是用HSDB工具看到的,jdk自带的工具
在这里插入图片描述

不同方式创建字符串在JVM中的存在形式

双引号

这种方式可以创建String对象1个,也可以说创建了2个OOP对象:InstanceOopdesc和TypeArrayOopdesc
在这里插入图片描述
验证

在这里插入图片描述

new String

这种方式可以说创建String对象2个,也可以说创建了3个OOP对象:2个InstanceOopdesc和1个TypeArrayOopdesc.
为什么?
因为jvm创建字符串对象的时候会先在字符串常量池中去找,如果找到了就直接返回,如果没找到就会创建一个该字符串对象。然后他自己本身还new了一个String对象,所有就是两个String对象,三个oop对象
在这里插入图片描述
验证

在这里插入图片描述

两个双引号

这种方式可以说创建String对象1个,也可以说创建了2个OOP对象
为什么应该知道了把?验证我就不贴了,你们自己动手
在这里插入图片描述

两个new String

这种方式可以说创建String对象3个,也可以说创建了4个OOP对象

在这里插入图片描述

拼接字符串底层是怎么实现的

双引号 + 双引号

public class TestString_5 {

    public static void main(String[] args) {
			test2();
   }

    public static void test2() {
    	
        String s1 = "1";
        String s2 = "1";
        String s = s1 + s2; //会形成2个String对象,2个typeArrrayOop对象
        // String a = “1”+“2”;//只会形成1个String对象和1个typeOop对象
    }
}

字节码指令

 0 ldc #2 <1>
 2 astore_0
 3 ldc #2 <1>
 5 astore_1
 6 new #3 <java/lang/StringBuilder>
 9 dup
10 invokespecial #4 <java/lang/StringBuilder.<init>>
13 aload_0
14 invokevirtual #5 <java/lang/StringBuilder.append>
17 aload_1
18 invokevirtual #5 <java/lang/StringBuilder.append>
21 invokevirtual #6 <java/lang/StringBuilder.toString>
24 astore_2
25 return

可以看到字符串拼接底层是用的StringBuilder,最后再调用了toString方法。我们再来看看StringBuilder的toString方法,可以看到它底层也是new了一个String对象。但是注意这个对象不会进入常量池
在这里插入图片描述
验证不会加入常量池

如果会加入常量池,那么下面代码应该是相等的
在这里插入图片描述

双引号 + new

public class TestString_6 {

    public static void main(String[] args) {
		test2();
    }

    public static void test2() {
        String s1 = "1";
        String s2 = new String("1");

        String s = s1 + s2;
    }
}

字节码指令

0 ldc #2 <1>
 2 astore_0
 3 new #3 <java/lang/String>
 6 dup
 7 ldc #2 <1>
 9 invokespecial #4 <java/lang/String.<init>>
12 astore_1
13 new #5 <java/lang/StringBuilder>
16 dup
17 invokespecial #6 <java/lang/StringBuilder.<init>>
20 aload_0
21 invokevirtual #7 <java/lang/StringBuilder.append>
24 aload_1
25 invokevirtual #7 <java/lang/StringBuilder.append>
28 invokevirtual #8 <java/lang/StringBuilder.toString>
31 astore_2
32 return

可以看到也是一样的

String对象的intern方法

简单来说:就是查看常量池是否有该对象,如果没有就创建一个返回。
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值