Java中字符串池的底层机制?

2022-09-01 20:34:49

我很好奇为什么字符串可以在不调用的情况下创建,因为API提到它是一个new String()Objectclass java.lang.String

那么我们如何能够使用而不是?String s="hi"String s=new String("hi")

这篇文章澄清了运算符的使用和缺少,并说这是由于文字被禁留或从文字池中获取,因此是不可变的。==newStringJVMStrings

在看到诸如

String s="hi"

第一次真正发生了什么?

  1. 是否像这样替换它,其中创建一个对象并将其添加到字符串文本池中,因此后续调用(例如从池中获取)?JVMString s=new String("hi")"hi"String s1="hi"

  2. 底层机制就是这样运作的吗?如果是这样,则

    String s=new String("Test");
    String s1="Test";
    

    String s="Test";
    String s1="Test";
    

    在内存利用率和效率方面?

  3. 另外,有没有办法让我们访问字符串池来检查其中存在多少个文本,占用了多少空间等?String


答案 1

Java 编译器对字符串文本具有特殊支持。假设它没有,那么在源代码中创建字符串真的很麻烦,你必须写这样的东西:

// Suppose that we would not have string literals like "hi"
String s = new String(new char[]{ 'h', 'i' });

要回答您的问题:

  1. 或多或少,如果你真的想知道细节,你必须研究JVM的源代码,你可以在OpenJDK上找到,但要注意,它是庞大而复杂的。

  2. 不,这两者并不等同。在第一种情况下,您显式创建一个新对象:String

    String s=new String("Test");
    

    它将包含由文字 表示的对象的副本。请注意,用Java编写从来都不是一个好主意 - 字符串是不可变的,并且永远没有必要制作字符串文本的副本。String"Test"new String("some literal")

  3. 我不知道没有办法检查字符串池中有什么。


答案 2
  1. String s="hi"第一次真正发生了什么?

JVM是否像这样替换它,其中创建了一个对象,并将“hi”添加到字符串文本池中,因此从池中获取诸如String s1 = “hi”之类的后续调用?String s=new String("hi")

不。真正发生的事情是 - 字符串文本在编译时解析,并在类加载/初始化懒惰后立即进行暂存(添加到字符串常量池中)。因此,它们可供 JVM 中的类使用。请注意,即使字符串常量池中有一个字符串,其值为字符串,也会在堆上创建另一个字符串并返回其引用。"hi"new String("hi")

 String s=new String("Test"); 
 String s1="Test"; 

 String s="Test"; 
 String s1="Test"; 

在内存利用率和效率方面?

否,在第一种情况下,将创建 2 个“测试”字符串。一个将添加到 String 常量池(假设它尚未存在),另一个将添加到堆上。第二个可以在第二种情况下 GCed.In,字符串常量池中只存在一个字符串文本,并且有 2 个引用( 和 )。ss1

  1. 另外,如果有任何方法我们可以访问字符串池,例如检查程序或任何监视工具中存在多少字符串文本,占用的空间等?

我不认为我们可以看到字符串常量池的内容。我们只能根据我们的假设来假设确认行为。