A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 房建斌 中级黑马   /  2014-3-10 16:43  /  1497 人查看  /  4 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 房建斌 于 2014-3-11 11:35 编辑

利用反射修改String,修改之前,用substring方法截取了一个字符串,但是修改了原字符串后,截取的字符串的值也修改了。按理来说,substring返回的是一个新字符串,在字符串常量池中和原字符串不是共享的。照这个结果来看,substring方法还是和原字符串共享了一部分,并不是创建一个新的字符串了。请高手解答
  1.                 //jdk版本1.6.0_11
  2.                 String s1 = "Hello World";  
  3.                 String s2 = "Hello World";  
  4.                 String s3 = s1.substring(6);
  5.                
  6.                 System.out.println(s1); // Hello World  
  7.                 System.out.println(s2); // Hello World  
  8.                 System.out.println(s3); // World  
  9.                
  10.                 //得到String的value字段
  11.                 Field field = s1.getClass().getDeclaredField("value");
  12.                 //设置可访问
  13.                 field.setAccessible(true);
  14.                 //得到char数组的值
  15.                 char[] value = (char[])field.get(s1);
  16.                
  17.                 //更改数组的值
  18.                 value[6] = 'H';
  19.                 value[7] = 'e';
  20.                 value[8] = 'i';
  21.                 value[9] = 'm';
  22.                 value[10] = 'a';
  23.                
  24.                 System.out.println(s1); // Hello Heima  
  25.                 System.out.println(s2); // Hello Heima
  26.                 System.out.println(s3); //在修改之前加上s3 = s3.intern()结果为World,不加上结果为Heima。
复制代码



评分

参与人数 1技术分 +1 收起 理由
何伟超 + 1

查看全部评分

4 个回复

倒序浏览
我认为通过substring方法截取到的子串,然后赋给一个新的字符串变量,这时并没有在内存中开辟空间来单独存储,而是指向索引处,这样不仅获取了数据,而且节约了内存,不知道这样考虑对不对。
回复 使用道具 举报
如果String s3=s1.subString(6)只是将s3取值指向了内存中已有的常量字符串"Hello World"的某个索引处,
按这样理解的话,再创建一个String s4=s1.substring(6), 那s4和s3应该指向"Hello World"的同一索引处,s3==s4应该为ture吧?
但实际上
public class Test6{
   public static void main(String[] args){
       String s1 = "Hello World";  
       String s2 = "Hello World";  
       String s3 = s1.substring(6);
       String s4 = s1.substring(6);
       System.out.println(s1==s2);
       System.out.println(s3==s4);
   }
}
运行结果为true
               false
说明s1和s2是相等的,但是s3和s4是不等的,这个怎么解释?
---可能没必要深究的这么细,不过还是希望了解substring内情的给解答下~~~

评分

参与人数 1技术分 +1 收起 理由
何伟超 + 1

查看全部评分

回复 使用道具 举报

  1. <P>希望下面的例子能帮你解开疑惑。你是少了field.set(rtp2, newValue);
  2. 你需要使用Field对象把修改后的值给设置到对应的对象身上去。
  3. rtp2 就是你要设置的对象,而newValue就是你要设置的新的值 </P>
  4. <P>/**
  5. * 测试要求: 我们使用反射获取ReflectTestPoint字节码文件中的字段,把值里面的bbs更换成wwwweb
  6. * @param args
  7. */
  8. public static void main(String[] args) throws Exception {
  9. ReflectTestPoint rtp2 = new ReflectTestPoint();
  10. // 我们先获取字节码文件中的所有的对象
  11. // 因为我们的bean中是私有的字段所以我们使用DeclaredFields来进行获取
  12. // Field[] rtps=ReflectTestPoint.class.getDeclaredFields();
  13. Field[] rtps = rtp2.getClass().getDeclaredFields();
  14. // 遍历数组
  15. for (Field field : rtps) {
  16. // 因为里面有私有的方法所以我们需要开启暴力反射
  17. field.setAccessible(true); // 开启暴力反射
  18. // 获取字段的值
  19. // 如何判断字段的类型了
  20. // 如果字段是字符串的类型
  21. if (field.getType() == String.class) {
  22. // 获取里面的值
  23. // String oldValue=(String) field.get(new ReflectTestPoint());
  24. String oldValue = (String) field.get(rtp2);
  25. System.out.println("字段:" + field.getName() + "原始值:" + oldValue);
  26. /**
  27. * 字段都获取出来了 字段:itcastBBs原始值:bbs.itcast.com
  28. * 字段:itheimaBBs原始值:bbs.itheima.com
  29. * 字段:itcastWeb原始值:www.itcast.com
  30. * 字段:itheimaWeb原始值:www.itheima.com
  31. */
  32. // String newValue = oldValue.replace('b', 'w');
  33. String newValue=oldValue.replace("bbs", "www");
  34. // 将修改后的值设置给对象
  35. field.set(rtp2, newValue); // 使用字段对象把修改后的值设置给对象ReflectTestPoint中的字段
  36. System.out.println("更新后的数据:"+rtp2);
  37. /**
  38. * 字段:itcastBBs原始值:bbs.itcast.com
  39. 更新后的数据:wws.itcast.com:::==bbs.itheima.com:::==www.itcast.com:::==www.itheima.com
  40. 字段:itheimaBBs原始值:bbs.itheima.com
  41. 更新后的数据:wws.itcast.com:::==wws.itheima.com:::==www.itcast.com:::==www.itheima.com
  42. 字段:itcastWeb原始值:www.itcast.com
  43. 更新后的数据:wws.itcast.com:::==wws.itheima.com:::==www.itcast.com:::==www.itheima.com
  44. 字段:itheimaWeb原始值:www.itheima.com
  45. 更新后的数据:wws.itcast.com:::==wws.itheima.com:::==www.itcast.com:::==www.itheima.com
  46. */

  47. //怎么实现替换字符串了?
  48. /**
  49. * 字段:itcastBBs原始值:bbs.itcast.com
  50. 更新后的数据:www.itcast.com:::==bbs.itheima.com:::==www.itcast.com:::==www.itheima.com
  51. 字段:itheimaBBs原始值:bbs.itheima.com
  52. 更新后的数据:www.itcast.com:::==www.itheima.com:::==www.itcast.com:::==www.itheima.com
  53. 字段:itcastWeb原始值:www.itcast.com
  54. 更新后的数据:www.itcast.com:::==www.itheima.com:::==www.itcast.com:::==www.itheima.com
  55. 字段:itheimaWeb原始值:www.itheima.com
  56. 更新后的数据:www.itcast.com:::==www.itheima.com:::==www.itcast.com:::==www.itheima.com

  57. */
  58. }
  59. }
  60. }</P>
复制代码

评分

参与人数 1技术分 +1 收起 理由
何伟超 + 1

查看全部评分

回复 使用道具 举报
刚查看了一下Substring源码,substring会以当前字符串的字符数组为标准,返回一个新的字符串。所以多次substring的值是不相等的,虽然内容是一样的。由于substring是用了原来的数组字符串char[] value.所以当更改了原字符串的值的话,substring的内容也会随之更改。我是这么理解的。不知这么理解对不对,期待有大神的解答
  1.     public String substring(int beginIndex, int endIndex) {
  2.         if (beginIndex < 0) {
  3.             throw new StringIndexOutOfBoundsException(beginIndex);
  4.         }
  5.         if (endIndex > count) {
  6.             throw new StringIndexOutOfBoundsException(endIndex);
  7.         }
  8.         if (beginIndex > endIndex) {
  9.             throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
  10.         }
  11.         return ((beginIndex == 0) && (endIndex == count)) ? this :
  12.             new String(offset + beginIndex, endIndex - beginIndex, value);
  13.     }
复制代码



评分

参与人数 1技术分 +1 收起 理由
zzkang0206 + 1

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马