博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
String的可改变性
阅读量:5920 次
发布时间:2019-06-19

本文共 2235 字,大约阅读时间需要 7 分钟。

相信任何学习java的人,都会在书中看到“String字符串是不可变的,一旦创建就不能修改”这样的经典语句。也就是说写出String s = “aaa”; 之后再写 s = "bbb"; 还是没用,jvm会在内存中重新创建一个String对象“bbb”,而原来的“aaa”对象依然存在。 而且内存中“aaa”这个内容是不能修改的.这就是大多数人所接触的String以及对String 的解。

      不过经过我最近的研究,发现利用反射还是可以修改String对象。

      首先,研究String类源码,String类有一个 char 数组value,是final的,用来当作存储字符串的容器,也就是说String s=“aaa”;这个字符串真正是这么存储的: value[0]='a';  value[1]='a';  value[2]='a'; 而且value是final的,这就是说value在编译时就已经决定了。因此,这就是我们所说的String是不可变的。

      不过,当这一切的一切遇上java无敌的反射机制时,就好象防备森严的公主闺房下竟然有一条直通大街的地道,任何通过这条地道的人都可以一窥公主闺房。所以,通过Java的反射就可以改变String对象的内容。

      那么为什么反射就能改变String的内容呢?这是因为final是只对编译有效的,对运行无效。也就是说可以在运行是改变final的内容(当然前提是不能照着常规思路写,那样都不可能通过编译,怎么能运行呢?),所以你可以在运行时通过反射得到String的value的值,然后将新的值设置到value中,就改变了String对象。具体代码如下:

String s = "aaaa";        System.out.println(s);        try{            Field field = s.getClass().getDeclaredField("value"); //String 类含有一个名为value的char数组,用于存储            field.setAccessible(true);            if(null != field.get("value")){                System.out.println(field.get("value"));            }else{                System.out.println("no data");            }            field.set(s, new char[] {'b','b','b','b'});            System.out.println(s);        }catch(NoSuchFieldException e){            e.printStackTrace();        }catch(SecurityException e){            e.printStackTrace();        }catch(IllegalAccessException e){            e.printStackTrace();        }

运行结果如下:

aaaa[C@1d057dabbbb

只是简简单单的一句替代,运行结果就会改变,结果如下:

aa

[C@1d057da
bb
看到了吗?即使是下面new了一个大小为4的char数组,仍然只有两个‘b’存入到了s的value中。

这个好歹还没有抛出异常,要是替换成如下代码,更好的事情就来了,

String s = "aaaaaaa";

抛出异常如下:

aaaaaaa[C@1d057daException in thread "main" java.lang.ArrayIndexOutOfBoundsException	at java.lang.System.arraycopy(Native Method)	at java.lang.String.getChars(Unknown Source)	at java.io.BufferedWriter.write(Unknown Source)	at java.io.Writer.write(Unknown Source)	at java.io.PrintStream.write(Unknown Source)	at java.io.PrintStream.print(Unknown Source)	at java.io.PrintStream.println(Unknown Source)	at Test.main(Test.java:21)

呵呵,爽了吧。

由此可见,通过地道进入公主闺房毕竟不是见得阳光的事情,稍微有一点点不符合要求的都会被发现,只有当第一个char数组和第二个char数组的大小严格相等的时候才会出现我们期望的结果。

注:此文来自iteye飞檐走壁的博客,原文地址:http://james23dier.iteye.com/blog/626723,与大家分享

  

  

转载于:https://www.cnblogs.com/balderdasher/archive/2013/03/01/2938446.html

你可能感兴趣的文章
Altas在Ubuntu系统上的安装部署步骤
查看>>
nginx配置cache-control
查看>>
PostgreSQL的10进制与16进制互转
查看>>
volatile和synchronized的区别
查看>>
gns3 1.4.1 iou虚拟asa,ids
查看>>
我的友情链接
查看>>
使用ssh登录CentOS输入用户名后等待输入密码项慢
查看>>
KeyMob-国内移动广告平台领航者
查看>>
云计算与虚拟化工具之KVM
查看>>
css之margin 重叠现象
查看>>
每天一个linux命令(5):rm 命令
查看>>
实用的vi/vim 键盘图
查看>>
proguard 不混淆内部类的方法
查看>>
关于两个世界体系的对话
查看>>
netbeans encoding
查看>>
Java反序列化漏洞之weblogic本地利用实现篇
查看>>
Java 8新特性探究(4):类型注解 复杂还是便捷
查看>>
我的友情链接
查看>>
LVS集群系统详解
查看>>
微信开发 OAuth2.0 授权问题
查看>>