String 变量只要被赋值就等于新new一个String对象

引言

        字符串只要赋值就相当于新new一个对象,字符串变量指向这个新new的对象,之前的对象就成了没有引用指向的对象了。

 

看下面代码:

  1. public class Example {

  2.  
  3. String str = new String("good");

  4.  
  5. char[] ch = { 'a', 'b', 'c' };

  6.  
  7. public static void main(String args[]) {

  8.  
  9. Example ex = new Example();

  10.  
  11. ex.change(ex.str, ex.ch);

  12.  
  13. System.out.print(ex.str + " and ");

  14.  
  15. System.out.print(ex.ch);

  16.  
  17. }

  18.  
  19. public void change(String str, char ch[]) {

  20.  
  21. str = "test ok";

  22.  
  23. ch[0] = 'g';

  24.  
  25. }

  26. }


        结果输出是什么?

 

        我以为会是good and abc,因为形参无法改变实参的值嘛(值传递的时候应该是这样的),但是正确结果是good and gbc,后来明白,引用传递给形参(查了一些资料,有的说java当中只有值传递,没有引用传递;有的又说两种传递都有,我也弄不太清楚),然后在形参里面做改变的时候,实参也是会改变的,类比C语言的指针。原来如此,所以ch[0]的值会改变,可为什么字符串str的值又不变呢?我觉得有必要检查一下对象的hash码。

看下面的代码:

 

 
  1. public class Example {

  2.  
  3. String str = new String("good");

  4.  
  5. char[] ch = { 'a', 'b', 'c' };

  6.  
  7. public static void main(String args[]) {

  8.  
  9. Example ex = new Example();

  10.  
  11. ex.change(ex.str, ex.ch);

  12.  
  13. System.out.println("ex str hash"+ex.str.hashCode());//获得ex.str的hashcode

  14. System.out.println("ex ch hash"+ex.ch.hashCode());//获得ex.ch的hashcode

  15.  
  16. System.out.print(ex.str + " and ");

  17.  
  18. System.out.print(ex.ch);

  19.  
  20.  
  21.  
  22. }

  23.  
  24. public void change(String str, char ch[]) {

  25.  
  26. str = "test ok";

  27.  
  28. System.out.println("change str hash"+str.hashCode());//获得change 方法中str的hashcode

  29.  
  30. ch[0] = 'g';

  31.  
  32. System.out.println("ch hash"+ch.hashCode());//获得change 方法中ch的hashcode

  33. }

  34. }


 

 

就加了4行打印hash码,hash码输出如下:

        看到结果,发现在change方法中的数组和在main中的数组是同样的hashcode,说明修改的是同一个对象(该对象的实体在堆heap上),所以在change方法中修改了数组以后,main当中的ex.ch肯定也会被修改,因为是在堆上的同一个对象。

      但是,在change方法中的str和main当中的ex.str的hashcode居然是不一样的!!这说明在方法change中的形参str指向的并不是main当中的ex.str指向的对象,所以在change中做修改,当然不会影响main中的ex.str的对象的内容。

        那么问题来了,既然都是引用传递给形参,为什么数组的就是指向堆上的同一个对象,而字符串就不是指向同一个堆上的对象呢?

上面的代码稍作修改,如下:

 

 
  1. public class Example {

  2.  
  3. String str = new String("good");

  4.  
  5. char[] ch = { 'a', 'b', 'c' };

  6.  
  7. public static void main(String args[]) {

  8.  
  9. Example ex = new Example();

  10.  
  11. ex.change(ex.str, ex.ch);

  12.  
  13. System.out.println("ex str hash"+ex.str.hashCode());//获得ex.str的hashcode

  14. System.out.println("ex ch hash"+ex.ch.hashCode());//获得ex.ch的hashcode

  15.  
  16. System.out.print(ex.str + " and ");

  17.  
  18. System.out.print(ex.ch);

  19.  
  20.  
  21.  
  22. }

  23.  
  24. public void change(String str, char ch[]) {

  25.  
  26. System.out.println("change str hash"+str.hashCode());//获得change 方法中str的hashcode

  27. //<span style="color:#ff0000;">在str重新赋值之前就打印change方法中的形参str的对象的hashcode</span>

  28. str = "test ok";

  29.  
  30. ch[0] = 'g';

  31.  
  32.  
  33. System.out.println("ch hash"+ch.hashCode());//获得change 方法中ch的hashcode

  34. }

  35. }

 

 

输出结果为下:

      这时hashcode一样了。

      换句话说,在传递参数的时候,确实是引用传递过来,但是当重新给字符串赋值的时候,新赋值的字符串变量(引用)就不再指向原来的堆上的对象!

看下面代码:

 

 
  1. String s = "hello";

  2. System.out.println(s.hashCode());

  3. s = "world";

  4. System.out.println(s.hashCode());


输出结果:

 

      只要一赋值,对象的hashcode就改变,也就是说只要一赋值,就新生成一个对象,而不是在原对象上做更改。

      执行完这几行代码以后,在堆上面有两个对象!!一个是“hello”,一个是“world”。也就是说,在改变字符串的内容时,它没有在原来的堆内存上重写内容,而是新划出一块堆内存保存新赋的字符串内容!这个机制像什么?对,就是新new一个对象,所以我认为下面第2行和第3行代码是等价的:

 

 
  1. String s = "hello";

  2. s = "world";

  3. s = new String("world");

      s先指向new出的“hello”对象,当对s重新赋值的时候(执行第2行代码),s这个引用变量会指向新的一块堆内存所保存的对象“world”,而之前的”hello“对象会成为没有引用指向的对象,我认为不久就会被GC。

 

      至此,得出一个结论:字符串只要赋值就相当于新new一个对象,字符串变量指向这个新new的对象,之前的对象就成了没有引用指向的对象了。

 

--------------------- 本文来自 无扬人生 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/TheBlackbeard/article/details/52770048?utm_source=copy

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值