问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

String为什么是不可变的?

创作时间:
作者:
@小白创作中心

String为什么是不可变的?

引用
CSDN
1.
https://blog.csdn.net/2402_85030292/article/details/145532778

本文将深入探讨Java中String类为什么是不可变的,通过代码案例、String类的内部数据结构以及相关方法的使用来详细说明这一特性。

一、代码案例以演示String不可变的特性

1、final关键字

final可以用于修饰类、成员变量、成员方法

  • 当final修饰类时,表示这个类是一个“最终类”,也就是说,这个类不能被继承

下图中的Animal类就是一个被final修饰的类,所以在Dog类继承(extends)Animal类时,发生了报错。

  • final修饰成员变量时,该成员变量不能被改变或指向其他对象。

如果该成员变量是基本数据类型,那么数值被指定后将不能被改变,否则引发报错

如果该成员变量是引用类型,那么对该成员变量初始化后,不能改变指向,即不能指向其他对象

  • final修饰方法时,该方法不能被重写

Animal类是Dog类的父类,在Dog类中重写了feed方法,发生了报错,原因就是Animal类中的此方法用了final进行修饰

由此,我们来看看String类的源码:

String类在定义时,用了final关键字修饰,这就是一个最终类,使得String类不能被继承,避免了类的核心逻辑被修改

在定义并创建String类型的字符串时,在计算机中是将其转换成了char数组进行存放的,而源码中用于保存数据的数组value在声明时用final进行修饰,这就导致了String的指向不可变。

2、代码案例

案例一:通过赋值操作演示

public class Demo {
    public static void main(String[] args) {
        String oldWord = "Hello";
        System.out.println("原字符串: " + oldWord);
        // 尝试修改字符串,实际上是创建了一个新的 String 对象
        String newWord = oldWord + " World";
        System.out.println("原字符串内容: " + oldWord);
        System.out.println("修改后的字符串: " + newWord);
        System.out.println("原字符串是否改变: " + (oldWord == newWord));
    }
}  

通过比较
original

modified
的引用是否相等(
original == modified
),可以发现它们是不同的对象。最后输出
original
的内容,发现其值并没有改变

案例二: 通过方法调用演示

public class Demo {
    public static void main(String[] args) {
        String str = "abc";
        System.out.println("调用方法前的字符串: " + str);
        // 调用 replace 方法,该方法会返回一个新的 String 对象
        String newStr = str.replace('a', 'x');
        System.out.println("调用方法后返回的新字符串: " + newStr);
        System.out.println("原始字符串是否改变: " + (str == newStr));
        System.out.println("原始字符串内容: " + str);
    }
}  

比较
str

newStr
的引用,发现它们不相等,说明是不同的对象。最后输出
str
的内容,其值保持不变。

二、String类的内部数据结构及特点

1、String的内部数据结构

String的构造方法有:(其中三种)

其中,value是String类中存放数据的char数组,由此得出,String的内部数据结构是char数组,将String中的每一个字符依次存放到char数组中。

2、String类数据结构的特点

  • 不可变性
  • 底层实现基于字符数组
  • 比较操作只能使用equal关键字
  • 字符串池机制

三、String的某些方法,对于内容的修改会产生新的字符串对象

1、substring()

字符串截取,产生一个新的字符串,需要创建新对象去接收生成的字符串

public class Demo {
    public static void main(String[] args) {
        String a = "文学是人类精神世界的璀璨星辰,照亮我们漫漫人生旅途。";
        String sub1 = a.substring(6);
        String sub2 = a.substring(0, 6);
        System.out.println(a);
        System.out.println(sub1);
        System.out.println(sub2);
    }
}  

当传入一个参数时,则从指定下标(包括此下标)开始截取到整个字符串的末尾;当传入两个参数时,则从指定下标begin(包括)截取到指定下标end(不包括),常记:包前不包后。

2、toLowerCase()和toUpperCase()

大小写转换,将原字符串全转为大写/小写。均产生新的字符串

public class Demo {
    public static void main(String[] args) {
        String a = "abCdEFGhijK";
        String x = a.toLowerCase();
        String y = a.toUpperCase();
        System.out.println("原字符串:"+a);
        System.out.println("转小写后:"+x);
        System.out.println("转大写后:"+y);
    }
}  

toLowerCase():将原字符串全转为小写;toUpperCase():将原字符串全转为大写。

3、replace()和replaceAll()

替换,将原字符串中指定内容替换成指定内容。均产生新的字符串

public class Demo {
    public static void main(String[] args) {
        //replace
        String a = "#北京#上海#西安#成都#昆明";
        String replace = a.replace("#", "");
        System.out.println("原字符串:"+a);
        System.out.println("替换后:"+replace);
        //replaceAll
        String b = "1咸阳2宝鸡3渭南4榆林5延安";
        System.out.println("原字符串:"+b);
        String replaceAll = b.replaceAll("\\d", "");
        System.out.println("替换后:"+replaceAll);
    }
}  

replace():将原字符串中指定内容替换成指定内容;replaceAll()将将原字符串中指定内容(用正则表达式)替换成指定内容。

4、trim()

去除首尾空格,产生一个新的字符串

public class Demo {
    public static void main(String[] args) {
        //trim
        String x = " 在字里行间汲取力量 ";
        String y = x.trim();
        System.out.println("未处理的字符串:"+x);
        System.out.println("未处理的字符串长度:"+x.length());
        System.out.println("处理后的字符串:"+y);
        System.out.println("处理后的字符串:"+y.length());
    }
}  

以上都是个人见解与总结,如果错误,敬请指正;如有疑问,欢迎交流。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号