前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java避坑指南:Java中?java.lang.String你真的以为是不可变的吗?java11和java17是相同的结果吗?

Java避坑指南:Java中?java.lang.String你真的以为是不可变的吗?java11和java17是相同的结果吗?

作者头像
崔认知
发布2023-06-19 17:13:08
2220
发布2023-06-19 17:13:08
举报
文章被收录于专栏:nobodynobody

java.lang.String真是不可变的吗?在java11中,反射能修改值


反射修改string,导致string内容改变。

示例在java11版本下测试:

代码语言:javascript
复制
package com.example.demo;


import java.lang.reflect.Field;
import java.util.Arrays;

/**
 * @author 认知科技技术团队
 * 微信公众号:认知科技技术团队
 */
public class Demo {
    public static void main(String[] args) throws ReflectiveOperationException {
        String a = "崔认知";
        String b = "崔认知";
        System.out.println("反射更改String前");
        System.out.println(a);
        System.out.println(b);
        System.out.println(a.hashCode());
        System.out.println(b.hashCode());

        /////////////////////////////////////////
        Field value = String.class.getDeclaredField("value");
        value.setAccessible(true);
        byte[] byteValue = (byte[]) value.get(a);

        Arrays.fill(byteValue,  (byte)0);

        /////////////////////////////////////////
        System.out.println("反射更改String后");
        System.out.println(a);
        System.out.println(b);
        System.out.println(a.hashCode());
        System.out.println(b.hashCode());

    }
}

反射修改的关键是:获取内部的

代码语言:javascript
复制
 private final byte[] value;

byte数组,对此数组中值修改。

代码语言:javascript
复制
Field value = String.class.getDeclaredField("value");
value.setAccessible(true);
byte[] byteValue = (byte[]) value.get(a);

Arrays.fill(byteValue,  (byte)0);

结果:

字符串内容被修改,修改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 值没变,是因为字符串内部对此值做了缓存:

代码语言:javascript
复制
 /** Cache the hash code for the string */
    private int hash; // Default to 0
代码语言:javascript
复制
public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            hash = h = isLatin1() ? StringLatin1.hashCode(value)
                                  : StringUTF16.hashCode(value);
        }
        return h;
    }

虽然我们修改成功了,但是java也给我们打印了警告??日志,

代码语言:javascript
复制
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.example.demo.Demo (file:/Users/cuirenzhi/gitlab/demo1/target/classes/) to field java.lang.String.value
WARNING: Please consider reporting this to the maintainers of com.example.demo.Demo
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

我们这种反射修改字符串内部的数据是不合法的,反射底层会有校验。

java.lang.String真是不可变的吗?在java17中,反射就不能修改值


java17下运行的结果:

??java17中反射就不能修改值,java17中,不再已警告日志输出,而是直接异常输出控制台,再次抛出异常,我们的代码不能运行了

反射修改值做了很多限制:Module及Module导出权限、修改的值的权限(

PUBLIC、PRIVATE等权限)做了很多校验。

小结


java.lang.String,反射修改内部的

代码语言:javascript
复制
private final byte[] value

值,在java11和java17版本中有不同的行为结果:

  • java11中可以被修改,而且可能还会影响相同内容的其他字符串;
  • java17中不可以被修改,此时反射校验逻辑不通过,会抛出异常;

本文参与?腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-08-13,如有侵权请联系?cloudcommunity@tencent.com 删除

本文分享自 认知科技技术团队 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com