如题,大多数人都知道,因为String是被final修饰的,所以它不可变。那String为啥要被final修饰呢?可以从反方向考虑下,如果String可变会发生什么?

将方法或类声明为final主要目的是确保它们不会在子类中改变语义。String类是final类,这意味着不允许任何人定义String的子类。Java String最重要的一条约定就是不可变。

//String源码
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];
  1. String类用final关键字修饰,说明String不可继承。
  2. 字段value 是char【】数组,用final修饰,说明value这个引用地址不可变,但是Array数组是可变的。栈指针不可变,但是堆上的数据本体可以变。

不可变有什么好处:

  1. 安全:多线程下对资源做写操作有危险。不可变对象不能被写,所以线程安全。
  2. 可以共用一个实例(在多线程中共享一个不可变对象而不用担心线程安全问题):当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量进行检查,如果字符串常量池中存在相同内容的字符串对象的引用,则将这个引用返回,否则新的字符串对象被创建,然后将这个引用放入字符串常量池,并返回该引用。String one = “someString”;String two = “someString”,都用字面量“someString赋值”,他们其实都指向同一个内存地址。当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量进行检查,如果字符串常量池中存在相同内容的字符串对象的引用,则将这个引用返回,否则新的字符串对象被创建,然后将这个引用放入字符串常量池,并返回该引用。(PS:运行时常量池是方法区的一部分,用于存放各种字面量和符号引用)
  3. String是几乎每个类都会使用的类,特别是作为Hashmap之类的集合的key值时候,mutable的String有非常大的风险。