Java中的字符串池概念


String 对象是 Java 语言中最常用的类之一。Java 中的字符串是由字符数组内部支持的对象。由于数组是不可变的,字符串也是不可变的。每当对 String 进行更改时,都会创建一个全新的 String。
 
如何创建字符串
在java中有两种不同的方法来创建一个String对象。
第一种方法是使用文字或常量表达式:

String stringWithLiteral = "some Text"; //string literal
String stringWithConstant =
"some " + "Text"; //constant expression


第二种方法是使用“new”关键字:

String stringWithNew = "some Text";


不可变字符串
字符串是常量,这意味着它们的值在创建后无法更改。如果 String 在 Java 中不是不变的,则字符串池是不可能的。字符串在 Java 中是不可变的有一些原因。

  • 如果 String 不是不可变的,它将构成安全威胁。例如,用户名和密码作为字符串传递。字符串是不可变的,所以它的值在创建后不能改变。如果 String 不是不可变的,任何人都可以通过更改敏感信息在应用程序中引起安全问题。
  • 由于其不可变性,String 对于多线程是安全的。不同的线程可以访问单个“字符串实例”。它删除了线程安全的同步,因为我们隐式地使字符串线程安全。
  • JVM 类加载器在加载类时也使用字符串。不变性为 Classloader 加载正确的类提供了安全性。

 
字符串池
String Pool 是堆内存中的一个存储区域。对象分配在时间和内存的情况下都是昂贵的。JVM 在初始化 String 时执行一些步骤以提高性能并减少内存使用。为了减少在 JVM 中创建的 String 对象的数量,String 类保留了一个字符串池。
JVM 可以通过在池中仅存储每个文字字符串的一个副本来优化为字符串分配的内存量。这个过程称为字符串实习String Interning.。
当我们创建一个字符串字面量时,JVM 会在字符串池中搜索具有相等值的字符串。如果字符串已存在于字符串池中,则返回对池化实例的引用。如果字符串不存在于字符串池中,则会初始化一个新的字符串对象并将其放入字符串池中。
 
Java 中的字符串池是如何工作的
当我们使用文字或常量表达式创建新的 String 对象时,JVM 会检查 String Pool 中是否存在相同的值。
String str1 = "Java"
String str2 =
"Java"

如果字符串池已包含此字符串文字,则返回现有对象的实例。如果字符串池不包含此字符串文字,则会创建一个新字符串并将其添加到字符串池中。
如果要更改此行为,请使用 new 关键字创建一个字符串:
String str3 = new String("Java")

使用“new”关键字创建一个新的 String 实例,即使它已经在 String Pool 中。
Java 提供了一种称为 intern 的本地方法:使用这种方法,我们可以将此字符添加到字符串池中。此方法还返回实习字符串。
String str4 = str3.intern()

字符串池的代码示例
在展示 String Pool 的例子之前,需要提醒的是 Java 中的 == 运算符会检查内存中的地址是否相等。因此,我们将使用 == 运算符比较字符串以确保它们是相同的对象。

String str1 = "Java";
String str2 =
"Java";
String str3 = new String(
"Java");
String str4 = new String(
"Java").intern();        
System.out.println(str1 == str2);
// true
System.out.println(str1 == str3);
// false
System.out.println(str1 == str4);
// true