Java中的String

268 阅读2分钟

这是我参与更文挑战的第1天,活动详情查看: 更文挑战

1 不可变的String

  String对象是不可变,即String对象一旦被创建就不会再被修改。String类中每一个看起来可以改变String值的方法,实际上都是创建一个全新的String对象。

2 String如何保证不可变性

  首先,来看下 JDK1.8 中String类的源码。

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

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = -6849794470754667710L;
}

  在这段代码中,有两点需要关注的,一个是 final 的使用,一个是 private 的使用。

final 修饰符的作用

  • final 修饰类中的属性:表示该属性一旦完成初始化便不可改变。对于基本类型,则属性值初始化之后不再改变;对于引用类型,则指引用地址初始化之后不再改变。
  • final 修饰类中的方法:说明这种方法提供的功能已经满足当前要求,不需要进行扩展,并且也不允许任何从此类继承的类来重写这种方法。
  • final 修饰类:表示该类是无法被任何其他类继承的,意味着此类在一个继承树中是一个叶子类,并且此类的设计已被认为很完美而不需要进行修改或扩展。

final 修饰的 String,代表了 String 的不可继承性,final 修饰的 char[] 代表了被存储的数据不可更改性。但是:虽然 final 代表了不可变,但仅仅是引用地址不可变,并不代表了数组本身不会变。而 char[] 还被private修饰,保证 char[] 不会被外部直接修改。在 final 和 private 的作用下,保证了String的不可变性。

3 String为什么设计为不可变

  • 1、为了线程安全
  • 2、为了实现字符串池:如果String是可变的,多个引用指向同一个 String 对象时,其中一个引用改变了String对象的值,其他引用也将发生变更,导致发生混乱。这里对比下 Redis 的 String 对象,由于 Redis 中的String 对象不存在不可变性质,导致 Redis 无法实现非 int 编码的String对象池。
  • 为了实现String可以创建 HashCode 不可变性