目录

1.String为什么是不可变得?

1.1 “不可变”的概念?

1.2 怎么实现的?

1.2.1 为什么String类被final修饰?

1.2.2 为什么char value[] 被final修饰?

 2.优点?


最近在研究String,发现有些概念自己搞了很久才搞懂,为了方便有后来者学习,也为了让自己加深一下记忆。在此记录一下,如有错误,还请多多指正。

1.String为什么是不可变得?

1.1 “不可变”的概念?

        这里不可变指的是String指向字符串常量池中的常量是不可变得,但是可以改变引用的地址。并不是指Sting本身被赋值后就不能再改变了。

Java String不可变为什么还能赋值 string为何不可变_字符串

        当String a 被重新赋值时,不是修改常量池中的值,也就是“abcd”是不可修改的,可以开辟另外一个空间“abcdef”,改变Sting a的引用地址。

1.2 怎么实现的?

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

首先我们了解一下final的作用

  • final修饰的类,不能被继承。
  • final修饰的方法,不能被重写。
  • final修饰的变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,是指引用变量不能变,引用变量所指向的对象中的内容还是可以改变的,也就是说在对其初始化之后便不能再让其指向另一个对象。 

1.2.1 为什么String类被final修饰?

        String类被final修饰目的是:确保它们不会在子类中改变语义。String类是final类,这意味着不允许任何人定义String的子类。就是为了防止大家乱继承String,从而改变String的特性,这样就会打破成为共识的基本约定。

1.2.2 为什么char value[] 被final修饰?

        目的:保证String不变性。(这样才能实现字符串常量池)

问题:被final修饰一定能保证value[]的不变性吗?

        答案:不能

看如下代码: 

@Test
    public void finalTest02() {
        final char[] value = {'c', 'c', 'c'};
        System.out.println(value);
        //将索引位置为2的修改为b
        value[2] = 'a';
        System.out.println(value);
    }
    /**
     * 结果
     * ccc
     * cca
     */

    @Test
    public void finalTest(){
        final  char[] value = {'a','a','a'};
        char[] value2 = {'b','b','b'};
        value = value2;
        //此时会报错,证明被final修饰不能value不能被重新赋值。
    }

我们通过这段代码可以看出,仅仅被final修饰是不能保证Sting的不变性的。

真正保证String不变性的是

  1. private 关键字可以保证value不被其他类访问和修改。
  2. String 类没有提供修改这个字符串的方法。

 2.优点?

  1. 作为在java中经常被使用和访问的类,保证String的不变性可以实现字符串常量池(在jvm方法区中),不用频繁的创建对象,可以节省内存空间
  2. 因为String是不可变的,多线程对同一个String操作时,不用考虑安全性的问题。因为是线程安全的。
  3. String很适合做Map的key。因为String有个成员变量hash
/** Cache the hash code for the string */
    private int hash; // Default to 0

保存的是 String 对象的 HashCode。因为 String 是不可变的,所以对象一旦被创建之后,HashCode 的值也就不可能变化了,我们就可以把 HashCode 缓存起来。这样的话,以后每次想要用到 HashCode 的时候,不需要重新计算,直接返回缓存过的 hash 的值就可以了,因为它不会变,这样可以提高效率,所以这就使得字符串非常适合用作 HashMap 的 key。