Java中String类型为什么不可变?

红太狼 2024-04-29 11:14 207阅读 0赞

1.源码中String类不可变的原因

String类的源码

  1. public final class String{
  2. //用字符数组来存数值
  3. private final char value[];
  4. }

虽然String是final类型的类,且value也是final类型的数组,但这不是String不可变的根本原因,String不可变是因为value是private,且并没有提供对外的get和set

final关键字修饰作用

修饰类:表明该类不可被继承,类中的所有成员方法都隐式的被指定为final方法

修饰方法:不可被重写,JVM会尝试将其内联,以提高运行效率

修饰变量:不可被改变,修饰引用变量表示引用不可变,引用指向的内容可变

修饰常量:在编译阶段会存入常量池中

2.如何改变String类的内容

String的值是不能被改变的,可能有人看到下面这个会觉得String的内容有被改变。但是实际上在内存中没改变的不是String 的值而是改变了引用的对象。然后将指针指向新的String 对象。所以经常改变内容的字符串最好不要用String,因为每次生成对象都会对系统性能产生影响。如果要改变字符串的内容,可以用StringBuffer与StringBuilder.

1.第一种

  1. public static void main(String[] args) {
  2. String s = "hey";
  3. s=s+" how are you";
  4. System.out.println(s);
  5. }
  6. //输出的值为 “hey how are you”

2.第二种对于引用类型,会在堆中创建实例,然后对象的具体指只在栈中进行保存。堆种保存的值栈种保存的值栈种对应的引用地址。

String中的value是引用类型,所以可以做到在不改变堆中引用的情况下,改变栈中具体的值即可

代码示例

  1. public class StringModifyTest {
  2. public static void main(String[] args) throws Exception{
  3. // 1. mock一个String
  4. String str = "Melodfy";
  5. // 2. 通过反射过去对象
  6. // 反射获取对象的三种方法
  7. // 1. Class.forName("类全限定名")
  8. // 2. 类名.class()
  9. // 3. 实例.getClass()
  10. Class<? extends String> strCls = str.getClass();
  11. // 3. 通过反射获取指定参数,得到一个属性对象
  12. Field field = strCls.getDeclaredField("value");
  13. // 私有属性要设置可访问,否则访问操作时异常
  14. filed.setAccessible(true);
  15. // 4. 根据属性对象获取参数的具体指
  16. char[] result = (char[])field.get(str);
  17. // 5. 验证输出结果
  18. Systemg,out.println("变更前结果:");
  19. for(char c : result) {
  20. System.out.print(c);
  21. }
  22. // 6. 操作变更,然后输出验证
  23. System.out.println("变更后结果:");
  24. char[2] = 'w';
  25. for(char c : result) {
  26. System.out.print(c);
  27. }
  28. }
  29. }

3.不可变的好处和坏处

1)线程安全性(好处)

在并发场景下,多个线程读取同一个资源,是不会引发竞态条件的。只有在对资源进行些操作时才有危险。不可变对象不能被修改,所以是线程安全的。

2)节省空间,提高效率(好处)

String还有字符串常量池的属性,on和two两个变量指向的是同一个地址。在大量使用字符串的情况下,可以节省内存空间,提高效率。

String的不可变条件是必要条件,要是内存中字符串内容能够改来改去,这么做就完全没有意义。

3)修改性能不高(坏处)

由于String 的不可变性,每次对String 类型进行改变的时候,都会生成一个新的String 对象,然后将指针指向新的String对象。

4.总结:

1.保存字符串的数组被final修饰且为私有的,并且String类没有提供/暴露修改这个字符串的方法

2.String类被final修饰导致其不能被继承,进而避免了子类破坏String 不可变

发表评论

表情:
评论列表 (有 0 条评论,207人围观)

还没有评论,来说两句吧...

相关阅读