`
james23dier
  • 浏览: 530157 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

论String字符串的可改变性

阅读更多

      相信任何学习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数组的大小严格相等的时候才会出现我们期望的结果。

0
0
分享到:
评论

相关推荐

    JAVA小论文(浅谈String类)

    String类在存储和处理字符串时非常有效,但是创建对象后,字符串的内容一旦确定则不可以改变,只可以改变其指向。字符串的替换也成了常用的操作。字符串的替换可以实现字符串的内容的部分“修改”。字符串对象可以...

    c++版的字符串加解密程序,huffman算法

    在加解密程序中,Huffman编码可以用于将原始字符串转换成一种“压缩”形式,这种形式在不改变数据内容的情况下,减少了数据量,增加了安全性。例如,通过构建Huffman树,可以为每个字符生成唯一的二进制码,然后将...

    论文研究 - 订阅数字图书馆和相应的期刊影响:一种基于价值的数字研究数据需求方法—儒家课程与“市场字符串”数字教育系统的整合

    文章关键词“Confucian Dao and Li, String Classification and Integration of Curricula, Digital Libraries”强调了儒家的道和礼在教育课程整合中的重要性,同时指出在课程整合中需要进行字符串分类,以及数字...

    字符串计算器:通过编码,重构和测试优先(TDD)的练习创建的字符串计算器

    例如,避免对整个输入字符串进行多次遍历,可以考虑使用集合结构一次性处理所有数字。 7. **设计模式**: - 尽管字符串计算器相对简单,但可以引入设计模式来提升代码质量。例如,使用工厂模式创建不同类型的...

    C 程式码比对分类

    - **精确与近似字符串匹配** (Exacting & Approximate String Matching): 包括精确匹配和近似匹配两种类型。精确匹配寻找完全相同的字符串模式;近似匹配则允许一定程度的错误或差异。 - **动态规划** (Dynamic ...

    StringCalculator:TDD StringCalculator卡塔

    StringCalculator是一个基础的字符串处理类,它接受一个包含数字的字符串,并返回这些数字的总和。 首先,让我们了解TDD的基本步骤:Red-Green-Refactor(红-绿-重构)。在"红"阶段,我们编写一个断言失败的测试...

    java记事本课设论文

    - `String(byte[] bytes)`: 通过byte数组构造字符串对象。 - `String(byte[] bytes, int offset, int length)`: 通过指定位置和长度的byte数组构造字符串对象。 - `String(char[] value)`: 通过char数组构造字符...

    3 Implementation Models for Scheme

    字符串基模型(String-Based Model) 字符串基模型是一个前瞻性的设计,主要针对多处理器环境下的Scheme实现。该模型将这些数据结构的版本直接嵌入到程序文本中,后者被表示为一系列符号组成的字符串。在此模型下...

    JAVA面试题集整理

    - **解释**:`String` 是不可变的,每次拼接都会创建新的字符串对象,因此在频繁拼接时效率较低;而 `StringBuffer` 是可变的字符串缓冲区,可以高效地进行字符串拼接操作。另外,`StringBuffer` 还提供了线程安全...

    基于J2EE框架的个人博客系统项目毕业设计论文(源码和论文)

    随着博客人数的增加, Blog 作为一种新的生活方式、新的工作方式、新的学习方式已经被越来越多的人所接受,并且在改变传统的网络和社会结构:网络信息不再是虚假不可验证的,交流和沟通更有明确的选择和方向性,单一...

    你应该更新的Java知识

    - **敏捷与精益方法论的普及**:敏捷开发方法论(如Scrum和Kanban)以及精益思想已经被广泛采纳,它们改变了软件项目的管理方式,提高了开发效率和产品质量。 - **现代Web框架的影响**:Ruby on Rails等现代Web框架...

    SAp笔试试题

    在Java中,`String`是不可变的字符串类,这意味着一旦创建了一个`String`对象,其值就不能改变。每次对`String`对象进行修改时,都会创建一个新的`String`对象。而`StringBuffer`是可变的字符串类,可以在不创建新...

    讲结构化程序设计PPT学习教案.pptx

    结构化程序设计是一种编程方法论,它强调程序的清晰性和模块化,以提高代码的可读性、可维护性和可重用性。本教程重点介绍了C语言中的结构化程序设计概念,包括C程序的基本结构、函数基础知识以及文件的简单用法。 ...

    4747 Java语言程序设计(一)

    - 字符串是不可变的对象,一旦创建就不能改变。 **4.6 确定字符数组长度与确定字符串长度的不同** - 字符数组的长度可以通过`length`属性获得。 - 字符串的长度同样通过`length()`方法获得。 **4.7 大小写转换** ...

    java实习周记25篇通用

    - **String和StringBuilder**:String是不可变对象,StringBuilder是可变的,用于构建和修改字符串。 4. **高级Java语法**: - **继承**:子类可以继承父类的属性和方法,super关键字用于在子类中引用父类的成员...

    java面试笔试题用到的

    - **数值型字符转数字**:可以使用`Character.getNumericValue(char)`方法或者通过`Integer.parseInt(String)`和`Double.parseDouble(String)`等方法将字符串转换为数值。 - **数字转字符**:使用`Character....

    tcl and the tk toolkit PART3

    最后,介绍了字符串匹配(String matching)的技术,这对于实现高效的文本搜索和过滤非常有用。 ### 第35章:POSIX实用程序 POSIX实用程序为开发人员提供了多种操作系统级别的功能。本章首先介绍了波浪号扩展(Tilde ...

    Thinking In C++ VolumeII.pdf

    - **STL字符串类**:`std::string` 类提供了丰富的字符串操作功能,如拼接、查找、替换等。 - **字符串流**:`std::stringstream` 是一种方便的工具,用于将字符串转换为其他类型的数据,反之亦然。 - **字符编码**...

Global site tag (gtag.js) - Google Analytics