Java 避坑指南:Java 中 java.lang.String 你真的以为是不可变的吗?java11 和 java17 是相同的结果吗?
![Java避坑指南:Java中 java.lang.String你真的以为是不可变的吗?java11和java17是相同的结果吗?](https://static001.geekbang.org/infoq/62/62eba8a797302834494641a249b792f0.jpeg)
java.lang.String 真是不可变的吗?在 java11 中,反射能修改值
反射修改 string,导致 string 内容改变。
示例在 java11 版本下测试:
反射修改的关键是:获取内部的
数组,对此数组中值修改。
结果:
![](https://static001.geekbang.org/infoq/67/6710f25bbee5550f756de9ab26617d6e.png)
字符串内容被修改,修改 a,但是 b 也被修改了,这和 jvm 中的 String Pool 有关系,可以参考 Caching the String literals and reusing them saves a lot of heap space because different String variables refer to the same object in the String pool. String intern pool serves exactly this purpose.https://www.baeldung.com/java-string-immutable#1-introduce-tostring-pool
但是 hashCode 值没变。hashCode 值没变,是因为字符串内部对此值做了缓存:
虽然我们修改成功了,但是 java 也给我们打印了警告⚠️日志,WARNING: An illegal reflective access operation has occurredWARNING: Illegal reflective access by com.example.demo.Demo (file:/Users/cuirenzhi/gitlab/demo1/target/classes/) to field java.lang.String.valueWARNING: Please consider reporting this to the maintainers of com.example.demo.DemoWARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operationsWARNING: All illegal access operations will be denied in a future release
我们这种反射修改字符串内部的数据是不合法的,反射底层会有校验。
![](https://static001.geekbang.org/infoq/f4/f41fbe413e5799ada4535ccadc3ab55f.png)
java.lang.String 真是不可变的吗?在 java17 中,反射就不能修改值
java17 下运行的结果:
![](https://static001.geekbang.org/infoq/06/06a97999156a6ad2054bf722347d46c4.png)
⚠️java17 中反射就不能修改值,java17 中,不再已警告日志输出,而是直接异常输出控制台,再次抛出异常,我们的代码不能运行了。
图片
图片
反射修改值做了很多限制:Module 及 Module 导出权限、修改的值的权限(PUBLIC、PRIVATE 等权限)做了很多校验。
小结
java.lang.String,反射修改内部的 private final byte[] value 值,在 java11 和 java17 版本中有不同的行为结果:
java11 中可以被修改,而且可能还会影响相同内容的其他字符串;
java17 中不可以被修改,此时反射校验逻辑不通过,会抛出异常;
版权声明: 本文为 InfoQ 作者【崔认知】的原创文章。
原文链接:【http://xie.infoq.cn/article/083498ee47fb7cb411139a645】。
本文遵守【CC BY-NC】协议,转载请保留原文出处及本版权声明。
评论