ublic class StringTest

 今天朋友问我String的内容是真的不可变吗?我肯定告诉他是的?因为在我的主观意识里String就是一个不可变的对象。于是他给我发了这段程序:

  p

 今天朋友问我String的内容是真的不可变吗?我肯定告诉他是的?因为在我的主观意识里String就是一个不可变的对象。于是他给我发了这段程序:

  public class StringTest {

  public static void main(String[] args) throws Exception {

  String a = chenssy;

  System.out.println(a =  + a);

  Field a_ = String.class.getDeclaredField(value);

  a_.setAccessible(true);

  char[] value=(char[])a_.get(a);

  value[4]='_';   //修改a所指向的值

  System.out.println(a =  + a);

  }

  }

  看到这个简单的程序,我笑了,你这不是从底层来修改String的值么?从这里来理解String的值肯定是可以改变的啦(我们应该始终相信String的不可变性)!接着他再给我一段程序:

  public class StringTest {

  public static void main(String[] args) throws Exception {

  String a = chenssy;

  String b = chenssy;

  String c = new String(chenssy);

  System.out.println(--------------修改前值-------------------);

  System.out.println(a =  + a);

  System.out.println(b =  + b);

  System.out.println(c =  + c);

  //修改String的值

  Field a_ = String.class.getDeclaredField(value);

  a_.setAccessible(true);

  char[] value=(char[])a_.get(a);

  value[4]='_';   //修改a所指向的值

  System.out.println(--------------修改后值-------------------);

  System.out.println(a =  + a);

  System.out.println(b =  + b);

  System.out.println(chenssy);

  System.out.println(c =  + c);

  }

  }

  乍看这程序是异常的简单,无非就是赋值、改值、输出嘛!可能你现在就会毫不犹豫的说太简单了结果就是……但是!!你的毫不犹豫会害死你,而且你的结果很可能错误。那么运行结果是什么呢?

  --------------修改前值-------------------

  a = chenssy

  b = chenssy

  c = chenssy

  --------------修改后值-------------------

  a = chen_sy

  b = chen_sy

  chen_sy

  c = chen_ssy

  修改前值很容易理解,但是修改后值呢?是不是有点儿不理解呢?你可能会问:为什么System.out.println(chenssy);的结果会是chen_ssy,System.out.println(c = + c);也是chen_ssy呢?

  要明白这个其实也比较简单,掌握一个知识点:字符串常量池。

  我们知道字符串的分配和其他对象分配一样,是需要消耗高昂的时间和空间的,而且字符串我们使用的非常多。JVM为了提高性能和减少内存的开销,在实例化字符串的时候进行了一些优化:使用字符串常量池。每当我们创建字符串常量时,JVM会首先检查字符串常量池,如果该字符串已经存在常量池中,那么就直接返回常量池中的实例引用。如果字符串不存在常量池中,就会实例化该字符串并且将其放到常量池中。由于String字符串的不可变性我们可以十分肯定常量池中一定不存在两个相同的字符串(这点对理解上面至关重要)。

  public static void main(String[] args) throws Exception {

  String a = chenssy;

  System.out.println(a =  + a);

  Field a_ = String.class.getDeclaredField(value);

  a_.setAccessible(true);

  char[] value=(char[])a_.get(a);

  value[4]='_';   //修改a所指向的值

  System.out.println(a =  + a);

  }

  }

  看到这个简单的程序,我笑了,你这不是从底层来修改String的值么?从这里来理解String的值肯定是可以改变的啦(我们应该始终相信String的不可变性)!接着他再给我一段程序:

  public class StringTest {

  public static void main(String[] args) throws Exception {

  String a = chenssy;

  String b = chenssy;

  String c = new String(chenssy);

  System.out.println(--------------修改前值-------------------);

  System.out.println(a =  + a);

  System.out.println(b =  + b);

  System.out.println(c =  + c);

  //修改String的值

  Field a_ = String.class.getDeclaredField(value);

  a_.setAccessible(true);

  char[] value=(char[])a_.get(a);

  value[4]='_';   //修改a所指向的值

  System.out.println(--------------修改后值-------------------);

  System.out.println(a =  + a);

  System.out.println(b =  + b);

  System.out.println(chenssy);

  System.out.println(c =  + c);

  }

  }

  乍看这程序是异常的简单,无非就是赋值、改值、输出嘛!可能你现在就会毫不犹豫的说太简单了结果就是……但是!!你的毫不犹豫会害死你,而且你的结果很可能错误。那么运行结果是什么呢?

  --------------修改前值-------------------

  a = chenssy

  b = chenssy

  c = chenssy

  --------------修改后值-------------------

  a = chen_sy

  b = chen_sy

  chen_sy

  c = chen_ssy

  修改前值很容易理解,但是修改后值呢?是不是有点儿不理解呢?你可能会问:为什么System.out.println(chenssy);的结果会是chen_ssy,System.out.println(c = + c);也是chen_ssy呢?

  要明白这个其实也比较简单,掌握一个知识点:字符串常量池。

  我们知道字符串的分配和其他对象分配一样,是需要消耗高昂的时间和空间的,而且字符串我们使用的非常多。JVM为了提高性能和减少内存的开销,在实例化字符串的时候进行了一些优化:使用字符串常量池。每当我们创建字符串常量时,JVM会首先检查字符串常量池,如果该字符串已经存在常量池中,那么就直接返回常量池中的实例引用。如果字符串不存在常量池中,就会实例化该字符串并且将其放到常量池中。由于String字符串的不可变性我们可以十分肯定常量池中一定不存在两个相同的字符串(这点对理解上面至关重要)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值