看java String类的不可变性

  常遇到面试说,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;
    }





猜你喜欢

转载自blog.csdn.net/jackyemail/article/details/80222060