字符串
由于 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)。