String的不可变理解

一、什么是不可变

    如果一个对象它被创建后,状态不能改变,则这个对象被认为是不可变的。

 二、怎么实现不可变

当使用final修饰基本类型变量时,不能对基本类型变量重新赋值,因此基本类型变量不能被改变。但对于引用类型变量而言,它保存的仅仅是一个引用,final只保证这个引用变量所引用的地址不会改变,即一直引用同一个对象,但这个对象完全可以发生改变。例如某个指向数组的final引用,它必须从此至终指向初始化时指向的数组,但是这个数组的内容完全可以改变。
即:被final修饰的java值不可变,首先java是值传递,

 

  • 引用传递(pass by reference)是指在调用方法时将实际参数的地址直接传递到方法中,那么在方法中对参数所进行的修改,将影响到实际参数。
  • 值传递(pass by value)是指在调用方法时将实际参数拷贝一份传递到方法中,这样在方法中如果对参数进行修改,将不会影响到实际参数。

Java是值传递。

1、当传的是基本类型时,传的是值的拷贝,对拷贝变量的修改不影响原变量;

2、当传的是引用类型时,传的是引用地址的拷贝,但是拷贝的地址和真实地址指向的都是同一个真实数据,因此可以修改原变量中的值;当传的是String类型时,虽然拷贝的也是引用地址,指向的是同一个数据,但是String的值不能被修改,因此无法修改原变量中的值。

1、对于基本数据类型是不可变,

2、对象保存的是引用,保证引用地址不变,但是引用内容可变。例如String类

String类的两个主要成员变量

value与hash。这里只对value做分析
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

    /** Cache the hash code for the string */
    private int hash; // Default to 0

 

value指向的是一个字符串数组,字符串中的字符就是用这个value变量存储起来的,并且用final修饰,也就是说value一旦赋予初始值之后,value指向的地址就不能再改变了。虽然value指向的数组是可以改变的,但是String也没有提供相应的方法让我们去修改value指向的数组的元素。然而在StringBuilder中是提供了响应的方法让我们去修改value指向的数组的元素,这也是StringBuilder的字符串序列可变的原因。

即:String类的地址没有改变,value指向的值可以改变。

例:

public static void main(String[] args) {
        String str1 = "hello";
        // 打印str1的内存地址
        System.out.println("str1的内存地址:" + System.identityHashCode(str1));
        String str2 = "world";
        str1 += str2;
        // str1的内存地址已经改变了
        System.out.println("执行+=后str1的内存地址:" + System.identityHashCode(str1));
        System.out.println("拼接之后str1的值:" + str1);

结果:

str1的内存地址:1922154895
执行+=后str1的内存地址:883049899
拼接之后str1的值:helloworld

 改变的是String类中value的值,而不是String类型的引用值。

 

posted @ 2021-04-19 09:45  清华大咖  阅读(774)  评论(0编辑  收藏  举报