字符串

由于 Java 字符串是不可变的 ,因此操作 String 的所有方法都将返回一个新的 String 对象。他们不会改变原来的 String。这包括 C 和 C++程序员期望改变目标 String 对象的子字符串和替换方法。

如果要连接两个以上在编译时无法确定其值的 String 对象,请使用 StringBuilder 而不是 String。这种技术比创建新的 String 对象和连接它们更有效,因为 StringBuilder 是可变的。

StringBuffer 也可以用来连接 String 对象。但是,此类的性能较差,因为它设计为线程安全的,并在每次操作之前获取互斥锁。由于在连接字符串时几乎从不需要线程安全性,因此最好使用 StringBuilder

如果你可以将字符串连接表达为单个表达式,那么最好使用+运算符。Java 编译器将使用 String.concat(...)StringBuilder 将包含+连接的表达式转换为有效的操作序列。显式使用 StringBuilder 的建议仅适用于串联涉及多个表达式时。

不要将敏感信息存储在字符串中。如果有人能够获取正在运行的应用程序的内存转储,那么他们将能够找到所有现有的 String 对象并读取其内容。这包括无法访问且正在等待垃圾收集的 String 对象。如果这是一个问题,你需要在完成后立即擦除敏感字符串数据。你不能用 String 对象做到这一点,因为它们是不可变的。因此,建议使用 char[] 对象来保存敏感字符数据,并在完成后擦除它们(例如,用'\000'字符覆盖它们)。

所有 String 实例是在堆上创建的,甚至是与字符串文字对应的实例。关于字符串文字的特殊之处在于 JVM 确保所有相等的文字(即由相同字符组成)由单个 String 对象表示(此行为在 JLS 中指定)。这是由 JVM 类加载器实现的。当类加载器加载一个类时,它会扫描在类定义中使用的字符串文字,每次看到它时,都会检查字符串池中是否已存在该文字的记录(使用文字作为键)。如果已存在文字的条目,则使用对作为该文字对的存储的 String 实例的引用。否则,将创建一个新的 String 实例,并为字符串池中的文字(用作键)存储对实例的引用。字符串实习 )。

字符串池保存在 Java 堆中,并受到正常的垃圾回收。

Version < Java SE 7

在 Java 7 之前的 Java 版本中,字符串池被保存在称为 PermGen 的堆的特殊部分中。这部分只是偶尔收集。

Version >= Java SE 7

在 Java 7 中,字符串池已从 PermGen 中移除。

请注意,可以从使用它们的任何方法隐式地访问字符串文字。这意味着如果代码本身是垃圾收集的,那么相应的 String 对象只能被垃圾收集。

直到 Java 8,String 对象被实现为 UTF-16 char 数组(每个字符 2 个字节)。在 Java 9 中有一个提议将 String 实现为带有编码标志字段的字节数组,以便注意字符串是否被编码为字节(LATIN-1)或字符(UTF-16)。