修改 class_Java 反射修改String引发的思考?

今天看到一篇文章,问题是《String 真的是不可变的吗?》,题主最后通过反射机制修改了String 内部的char[] 对象的值,最终完成了String 的修改。

这里先上原博主的示例:

// 创建字符串"Hello World", 并赋给引用s

运行结果

s 

看完这个问题,我的第一反应是,修改完成之后全局字符创常量池(StringPool)中的字符串引用数是一个还是两个,堆中存在的字符串实例是一个还是两个,然后我向验证我的想法。

验证代码

public 

运行结果

s1 

对于这个结果,我提出了我的想法(猜想)

c629cbb697231c0bff615496e2295574.png

首先第一行代码

String 

JVM 会现在全局字符串常量池中查找是否已经有了这个字符串实例(常量共享),如果没有则会在堆中创建"Hello World" 的字符串实例,然后在全局字符串常量池中创建其引用,全局字符串常量池通过一个StringTable 对象来存储这个引用关系,简单猜想就是以key-value 的格式存储,即StringHashCode-String实例引用的方式。最后s1 指向全局字符串常量池的引用。

紧接着是第二行代码

String 

JVM 通过在全局字符串常量池中查询到了已经存在该字符串实例然后直接返回该实例引用,所以s1 == s2 这个在意料之中,此时堆和字符串常量池也都只有这个字符串。

接下来就是反射修改String 的过程,通过反射获取到s1 的字符串存储对象(char[])并对其进行修改,由于s1、s2 指向的都是相同的实例,所以s1 的修改就等价于s2 的修改,所以修改完成之后,s1 == s2 依然成立,但是堆中的字符串实例已经发生改变,并且旧的实例"Hello World" 已经不存在。

再然后就是

String s3 = "Hello World";

这一步创建的时候,JVM 通过在全局字符串常量池中查询,发现已经有存在的StringHashCode,则直接返回对应的字符串实例,但是该字符串实例已经在上一步被修改成了"Hello_World",这也就导致s1 == s3 不成立。

最后就是

String s4 = "Hello_World"

JVM 在全局字符串常量池中查询,发现没有字符串实例,StringHashCode 不存在,则在堆中创建中字符串实例,并在全局字符串常量池中存储改关系,所以这一步完成之后,存在两个相同但不相等字符串对象实例"Hello_World",一个是通过"Hello World"修改而来的,另一个就是s4 创建的"Hello_World"。

还有一个猜想是Class 常量池,即在静态编译时,s1、s2 编译到到class 文件中,而s3 是运行时动态编译的,所以导致了该结果。

但是最重要的我想要验证这两个猜想,但不知道如何验证。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值