Intern:把堆区的字符串放入字符串常量池吧!

54 阅读3分钟

在 Java 中,Stringintern() 方法是一个非常重要的概念,它与 字符串常量池(String Constant Pool)密切相关。为了更好地理解它的工作原理,我们可以从实际例子出发。

1. String Intern() 方法概述

intern() 方法的作用是:

  • 如果字符串常量池中已经存在一个等价于当前 String 对象的字符串,则返回常量池中的字符串的引用。
  • 如果常量池中没有这个字符串,则将该字符串添加到常量池,并返回该字符串的引用。

这个方法主要用于优化内存,因为 Java 会确保相同内容的字符串只在内存中存在一个副本。

2. 常量池与 intern()

在 Java 中,所有通过字面量创建的字符串都会被自动加入到 字符串常量池 中。例如:

String s1 = "java";
String s2 = "java";

这里,s1s2 都指向常量池中的 "java" 字符串。

如果你显式调用 intern() 方法,则会强制将一个非字面量的字符串加入到常量池中,或者返回常量池中已存在的等价字符串。

3. 具体示例分析

让我们通过一个具体的例子来详细分析 intern() 的工作原理:

public class StringInternTest {
    public static void main(String[] args) {
        // 字面量创建的字符串
        String s1 = "hello";
        String s2 = "hello";  // 与s1引用相同

        // 使用new关键字创建的字符串
        String s3 = new String("hello");
        
        // 使用intern()方法
        String s4 = s3.intern();
        
        // 打印是否引用相同
        System.out.println(s1 == s2);  // true
        System.out.println(s1 == s3);  // false
        System.out.println(s1 == s4);  // true
    }
}

4. 代码逐步分析

  • String s1 = "hello";

    • 这是一个字面量字符串,它会直接指向字符串常量池中的 "hello"
  • String s2 = "hello";

    • 由于字面量 "hello" 已经在常量池中,s2 会直接引用常量池中的 "hello",与 s1 指向同一个内存位置。
  • String s3 = new String("hello");

    • 这是通过 new 关键字创建的字符串,它不直接指向常量池中的 "hello",而是指向堆内存中的一个新对象。虽然 "hello" 这个字符串字面量已存在常量池中,但 new String("hello") 会在堆中创建一个新的 String 对象。
  • String s4 = s3.intern();

    • s3 是通过 new 创建的字符串对象,调用 intern() 方法时,会检查常量池中是否已经存在 "hello"
    • 由于常量池中已经有 "hello",所以 intern() 方法返回常量池中的 "hello",并将 s4 引用指向常量池中的字符串 "hello"

5. 输出结果分析

System.out.println(s1 == s2);  // true
System.out.println(s1 == s3);  // false
System.out.println(s1 == s4);  // true
  • s1 == s2 输出 trues1s2 都指向常量池中的 "hello",它们是同一个对象。
  • s1 == s3 输出 falses3 是通过 new 创建的字符串,它指向堆内存中的一个新对象,而 s1 指向常量池中的字符串,因此它们不是同一个对象。
  • s1 == s4 输出 trues4 是通过 s3.intern() 获取的,它指向常量池中的 "hello",与 s1 相同,因此它们是同一个对象。

6. 总结

  • 字面量创建的字符串会直接加入常量池。
  • 使用 new 创建的字符串会指向堆内存中的新对象,不会直接添加到常量池。
  • 调用 intern() 方法时,如果常量池中已经存在该字符串,则返回常量池中的引用;如果不存在,则将其添加到常量池中,并返回引用。

intern() 的关键作用是 优化内存,避免重复存储相同内容的字符串。如果有大量相同内容的字符串使用 intern(),可以节省内存。