通过反射改变String类的值

原文:https://www.jianshu.com/p/4d57ad5f8950
作者:Eric新之助

前面有篇文章:为什么String被设计成不可变 很多人挺感兴趣的,那么设计成不可变是不是就真的不可修改值呢,各位看官往下看。

通常认为String类对象是不可修改的,例如:

String s="abc";
s="123";
System.out.println(s);

首先创建一个String对象s,然后让s的值为“abc”, 然后又让s的值为“123”。 从打印结果可以看出,s的值确实改变了。

这里的s只是一个String对象的引用,并不是对象本身。

对象在内存中是一块内存区,成员变量越多,这块内存区占的空间越大。引用只是一个4字节的数据,里面存放了它所指向的对象的地址,通过这个地址可以访问对象。 也就是说,s只是一个引用,它指向了一个具体的对象,当s=“123”; 这句代码执行过之后,又创建了一个新的对象“123”, 而引用s重新指向了这个新的对象,原来的对象“abc”还在内存中存在,并没有改变。

String 类的成员对象有

private final char[] value;
private final int offset;
private final int count;

value,offset和count这三个变量都是private的,并且没有提供setValue, setOffset和setCount等公共方法来修改这些值,所以在String类的外部无法修改String。也就是说一旦初始化就不能修改, 并且在String类的外部不能访问这三个成员。此外,value,offset和count这三个变量都是final的, 也就是说在String类内部,一旦这三个值初始化了, 也不能被改变。
所以可以认为String对象是不可变的了。

但,可以通过反射改变String value的值

   String s = "abcd";       

   System.out.println("s = " + s); 

   Field valueField = String.class.getDeclaredField("value");     

   valueField.setAccessible(true);      

   char[] value = (char[]) valueField.get(s);       

   value[3] = 'e';      
   System.out.println("s = " + s);  

   valueField.set(s, new char[]{'1''2''3'});       

   Field countField = String.class.getDeclaredField("count");
   countField.setAccessible(true);
   countField.set(s, 3);
   System.out.println("s = " + s);

特别注意

通过发射修改String的值的时候,特别要注意维护好count的值,因为修改后的字符串长度可能已经改变。看String源码,length方法就是返回count的值。如下:

public int length() {
   return this.count;
}


推荐阅读

程序员从深圳回到武汉,有这么难吗?

为什么String被设计成不可变

【分布式】数据库和缓存双写一致性方案解析

640

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值