关于String的一点知识

相信大部分准备过java面试的同学都知道Java中的String是final修饰,不可变的。可是只知道是什么,不知道为什么是一件非常危险的事情。因为任何事情都没有绝对。

我们先看看什么是不可变对象。

什么是不可变对象?

如果一个对象,在创建完成之后,不能在改变他的状态。(包括内部成员变量,基本数据类型。引用类型的变量不能指向其他对象,引用类型指向的对象的状态)对象则认为不可改变。

关于Java中的String不可变的原因,具体可以参考下面这篇文章。

Java中的String不可变的原因

文中源码一直分析到了1.7,但是1.8之后,String源码又改动。

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {

    // The associated character storage is managed by the runtime. We only
    // keep track of the length here.
    //
    // private final char value[];
    private final int count;

    /** Cache the hash code for the string */
    private int hash; // Default to 0
    ....
   }

注释中我们可以看到,已经把字符存储放到runtime里面去了。而且内部修改字符串,也不再是简单的new String出来。

public String replace(char oldChar, char newChar) {
    String replaced = this;
    if (oldChar != newChar) {
        for (int i = 0; i < count; ++i) {
            if (charAt(i) == oldChar) {
                if (replaced == this) {
                    replaced = StringFactory.newStringFromString(this);
                }
                replaced.setCharAt(i, newChar);
            }
        }
    }
    return replaced;
}

采用了StringFactory.newStringFromString(),这个是native方法。上述文章中提到了利用反射修改不可访问的value,从而使不可变String,变成可变String。貌似在1.8中已经被封杀了。

String类不可变的好处:

  • 字符串池实现的前提。在运行时节约heap空间。不同字符串变量都指向同一个字符串。
  • 保障安全。直接影响:账号,密码等都以字符串的形式传递;隐形影响:HashSet,存储String内容,如果可变,破坏键值的唯一性。
  • 多线程安全。
  • 缓存Hashcode,高效。String不可变,hashcode就是一个定值。不需要重新计算,所以作为map中的键,处理速度会更快。