String#intern 方法有什么作用?

String.intern() 是一个 native(本地)方法,应用于在字符串优化和内存管理方面。这个方法的作用是将当前字符串对象放到 Java 字符串常量池中(如果它还不在池中),并返回常量池中该字符串的引用。如果字符串常量池中已经包含了一个等于此 String 对象的字符串,则返回代表池中这个字符串的 String 对象的引用。

这里有几个关键点需要理解:

  1. 字符串常量池:Java 虚拟机(JVM)为了优化字符串存储,会维护一个特殊的存储区域,称为字符串常量池。这个池中的字符串是唯一的,即任何两个字符串如果内容相同,那么它们实际上是同一个对象。字符串常量池中的字符串可以是编译时常量,也可以是运行时常量(通过 String#intern() 方法添加)。

  2. intern() 方法的行为

    • 如果调用 intern() 方法的字符串对象已经存在于字符串常量池中,则返回常量池中该字符串的引用(注意,这是已经存在的字符串对象的引用,而不是当前对象的引用)。
    • 如果调用 intern() 方法的字符串对象不在字符串常量池中,那么该字符串对象将被添加到字符串常量池中,并返回该字符串对象的引用(此时,当前对象引用和返回的引用是相同的,因为当前对象已经被添加到了常量池中)。
  3. 性能优化:通过 intern() 方法,Java 应用程序可以减少字符串对象的数量,特别是当应用程序中使用了大量重复的字符串字面量时。因为所有重复的字符串都将引用字符串常量池中的同一个对象,这有助于减少内存占用和提高性能。

  4. 使用场景intern() 方法在需要比较大量字符串是否相等时特别有用,因为可以直接比较字符串对象的引用(如果它们已经被 intern() 处理过且相等),这比比较字符串内容要快得多。

  5. 注意:从 Java 7 开始,字符串常量池被移动到了堆内存中,而不是之前的永久代(PermGen space)。这一变化使得字符串常量池能够随着 Java 堆的大小动态扩展。

 举个例子帮助理解一下

public class StringInternExample {  
    public static void main(String[] args) {  
        // 使用字面量创建字符串,它会自动被添加到字符串常量池中  
        String str1 = "hello";  
          
        // 使用 new 关键字创建字符串对象,它不会在常量池中创建,而是在堆上创建  
        String str2 = new String("hello");  
          
        // 调用 intern() 方法,如果常量池中已存在 "hello",则返回常量池中的引用;否则,将 str2 添加到常量池中并返回其引用  
        String str3 = str2.intern();  
          
        // 比较 str1 和 str2  
        // 因为 str1 是字面量创建的,它直接指向常量池中的字符串;而 str2 是通过 new 创建的,它指向堆上的对象  
        // 所以 str1 != str2(它们引用不同的对象)  
        System.out.println(str1 == str2); // 输出:false  
          
        // 比较 str1 和 str3  
        // 因为 str3 是通过 intern() 方法从常量池中获取的 "hello" 的引用,而 str1 也是指向常量池中的 "hello"  
        // 所以 str1 == str3(它们引用相同的对象)  
        System.out.println(str1 == str3); // 输出:true  
          
        // 验证 str1 和 str2 的内容是否相同  
        // 尽管它们引用不同的对象,但内容相同  
        System.out.println(str1.equals(str2)); // 输出:true  
    }  
}

解释

  1. 字面量 vs. new 关键字
    • String str1 = "hello"; 这行代码使用字面量创建了一个字符串,这个字符串在编译时就被添加到了字符串常量池中。
    • String str2 = new String("hello"); 这行代码使用 new 关键字创建了一个新的字符串对象,这个对象被分配在堆上,而不是常量池中。同时,它也会检查常量池中是否已存在内容相同的字符串,但即使存在,也不会复用,而是会创建一个新的对象。
  2. intern() 方法
    • String str3 = str2.intern(); 这行代码调用了 intern() 方法。由于常量池中已经存在内容为 "hello" 的字符串(由 str1 引入),因此 intern() 方法不会添加新的字符串到常量池中,而是直接返回常量池中已存在的字符串的引用。因此,str3 和 str1 引用的是同一个对象。
  3. 比较操作
    • str1 == str2 比较的是两个对象的引用地址,由于它们指向不同的对象(一个在常量池,一个在堆上),所以结果为 false
    • str1 == str3 同样比较的是引用地址,但由于 str3 是通过 intern() 方法从常量池中获取的引用,与 str1 指向同一个对象,所以结果为 true
    • str1.equals(str2) 比较的是两个字符串的内容,由于它们的内容都是 "hello",所以结果为 true
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值