相信任何学习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@1d057da
bbbb
不过,通过反射还有有一些问题的:例如,如下的代码替代String s = "aaaa";
就会抛出异常:
String s = "aa";
只是简简单单的一句替代,运行结果就会改变,结果如下:
aa
[C@1d057da
bb
看到了吗?即使是下面new了一个大小为4的char数组,仍然只有两个‘b’存入到了s的value中。
这个好歹还没有抛出异常,要是替换成如下代码,更好的事情就来了,
String s = "aaaaaaa";
抛出异常如下:
aaaaaaa
[C@1d057da
Exception 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数组的大小严格相等的时候才会出现我们期望的结果。
分享到:
相关推荐
String类在存储和处理字符串时非常有效,但是创建对象后,字符串的内容一旦确定则不可以改变,只可以改变其指向。字符串的替换也成了常用的操作。字符串的替换可以实现字符串的内容的部分“修改”。字符串对象可以...
在加解密程序中,Huffman编码可以用于将原始字符串转换成一种“压缩”形式,这种形式在不改变数据内容的情况下,减少了数据量,增加了安全性。例如,通过构建Huffman树,可以为每个字符生成唯一的二进制码,然后将...
文章关键词“Confucian Dao and Li, String Classification and Integration of Curricula, Digital Libraries”强调了儒家的道和礼在教育课程整合中的重要性,同时指出在课程整合中需要进行字符串分类,以及数字...
例如,避免对整个输入字符串进行多次遍历,可以考虑使用集合结构一次性处理所有数字。 7. **设计模式**: - 尽管字符串计算器相对简单,但可以引入设计模式来提升代码质量。例如,使用工厂模式创建不同类型的...
- **精确与近似字符串匹配** (Exacting & Approximate String Matching): 包括精确匹配和近似匹配两种类型。精确匹配寻找完全相同的字符串模式;近似匹配则允许一定程度的错误或差异。 - **动态规划** (Dynamic ...
StringCalculator是一个基础的字符串处理类,它接受一个包含数字的字符串,并返回这些数字的总和。 首先,让我们了解TDD的基本步骤:Red-Green-Refactor(红-绿-重构)。在"红"阶段,我们编写一个断言失败的测试...
- `String(byte[] bytes)`: 通过byte数组构造字符串对象。 - `String(byte[] bytes, int offset, int length)`: 通过指定位置和长度的byte数组构造字符串对象。 - `String(char[] value)`: 通过char数组构造字符...
字符串基模型(String-Based Model) 字符串基模型是一个前瞻性的设计,主要针对多处理器环境下的Scheme实现。该模型将这些数据结构的版本直接嵌入到程序文本中,后者被表示为一系列符号组成的字符串。在此模型下...
- **解释**:`String` 是不可变的,每次拼接都会创建新的字符串对象,因此在频繁拼接时效率较低;而 `StringBuffer` 是可变的字符串缓冲区,可以高效地进行字符串拼接操作。另外,`StringBuffer` 还提供了线程安全...
随着博客人数的增加, Blog 作为一种新的生活方式、新的工作方式、新的学习方式已经被越来越多的人所接受,并且在改变传统的网络和社会结构:网络信息不再是虚假不可验证的,交流和沟通更有明确的选择和方向性,单一...
- **敏捷与精益方法论的普及**:敏捷开发方法论(如Scrum和Kanban)以及精益思想已经被广泛采纳,它们改变了软件项目的管理方式,提高了开发效率和产品质量。 - **现代Web框架的影响**:Ruby on Rails等现代Web框架...
在Java中,`String`是不可变的字符串类,这意味着一旦创建了一个`String`对象,其值就不能改变。每次对`String`对象进行修改时,都会创建一个新的`String`对象。而`StringBuffer`是可变的字符串类,可以在不创建新...
结构化程序设计是一种编程方法论,它强调程序的清晰性和模块化,以提高代码的可读性、可维护性和可重用性。本教程重点介绍了C语言中的结构化程序设计概念,包括C程序的基本结构、函数基础知识以及文件的简单用法。 ...
- 字符串是不可变的对象,一旦创建就不能改变。 **4.6 确定字符数组长度与确定字符串长度的不同** - 字符数组的长度可以通过`length`属性获得。 - 字符串的长度同样通过`length()`方法获得。 **4.7 大小写转换** ...
- **String和StringBuilder**:String是不可变对象,StringBuilder是可变的,用于构建和修改字符串。 4. **高级Java语法**: - **继承**:子类可以继承父类的属性和方法,super关键字用于在子类中引用父类的成员...
- **数值型字符转数字**:可以使用`Character.getNumericValue(char)`方法或者通过`Integer.parseInt(String)`和`Double.parseDouble(String)`等方法将字符串转换为数值。 - **数字转字符**:使用`Character....
最后,介绍了字符串匹配(String matching)的技术,这对于实现高效的文本搜索和过滤非常有用。 ### 第35章:POSIX实用程序 POSIX实用程序为开发人员提供了多种操作系统级别的功能。本章首先介绍了波浪号扩展(Tilde ...
- **STL字符串类**:`std::string` 类提供了丰富的字符串操作功能,如拼接、查找、替换等。 - **字符串流**:`std::stringstream` 是一种方便的工具,用于将字符串转换为其他类型的数据,反之亦然。 - **字符编码**...