当前位置 博文首页 > Jerry:看java String类的不可变性

    Jerry:看java String类的不可变性

    作者:[db:作者] 时间:2021-07-19 13:29

    ? 常遇到面试说,String为啥被设计成不可变的。看了下源码,说下个人看法:

    1、String的不可变 ??

    String a="hello";
    a="hello world";

    a 指向内存中常量池中"hello";后又被赋值为"hello world"。有人说这不是变化了吗?其实不然。原内容"hello"仍然存在于内存常量池中,a 指向了新的地址,常量池中“hello world”。

    ? ? ?这种a 所指向的内存地址发生变化,原地址所对应的值没有发生任何变化的现象,即为String 的不可变性。

    2、String 源码

    public final class String
        implements java.io.Serializable, Comparable<String>, CharSequence {
        /** The value is used for character storage. */
        private final char value[];

    从源码可以看出,首先 类被final修饰,也就是说不可以被继承,其次存储String 值的value 数组变量被封装在了类内部,不被外界访问,这就是为什么String 不可变的真实原因。

    3、好处

    ? ? >java 语言具有内存共享的机制,String 对象共享又是很重要的一部分-“常量池”。因为常量池的存在,程序可以节省大量的内存开支。

    ? ?> 正是因为String 的不可变性,保证了程序的安全性。由于共享机制的存在,假如String 可以变化,那么就是说被共享的任意字符串,都可能被程序其他部分修改,那么这点是相当不安全的。

    > 不可变对象不可写,所以多线程并发时,可以保证线程安全

    4、String 类的衍生,StringBuffer 和StringBuilder 为什么可变?

    public final class StringBuilder
        extends AbstractStringBuilder
        implements java.io.Serializable, CharSequence
    {
    ....
    
    
     public final class StringBuffer
        extends AbstractStringBuilder
        implements java.io.Serializable, CharSequence
    {
    

    从两个类的定义开头,我们可以看到,两个类也都被定义为了final 的,那么为什么却可以被改变呢?从定义中,我们可以看到,二者共同的父类为

    abstract class AbstractStringBuilder implements Appendable, CharSequence {
    
        /**
         * The value is used for character storage.
         */
        char[] value;

    可见,二者存储值的成员变量,value 是可以被子类对象通过append方法来进行修改的。

    >当字符长度,不超过value 初始长度时,将通过 value[index]= ...的方式填充value的值。此时,变量value数组对象引用地址没有变化,但是数组内容发生了变化。

    >当长度超过初始长度时,将会通过System.copyOf方法,将value所指向的内存中的值拷贝至新的更大容量的数组对象中。

    ? ?原数组对象,将被垃圾回收器回收。此时value整个引用对象发生变化,原数组对象值在新数组对象中得到了追加。

     public static char[] copyOf(char[] original, int newLength) {
            char[] copy = new char[newLength];
            System.arraycopy(original, 0, copy, 0,
                             Math.min(original.length, newLength));
            return copy;
        }






    cs