Java String intern方法介绍

本文探讨了Java中String对象的intern方法如何使不同对象地址的字符串在使用==操作符时返回true。通过示例代码展示了字符串常量池的工作原理及其实现方式。

今天看到有线程同步的代码直接使用了String对象作为锁对象,心想可能会出问题,因为String对象可能表面上内容一样,但是实际上却不是同一个对象地址。Java字符串比较 == 判断是地址是否相等,equals判断是内容是否相等。但是String类有个本地方法intern,可以让不同对象地址的字符串,使用==时返回true,来看下定义:


方法返回字符串对象的标准表示。重点在When段落。当字符串池中存在通过equals方法相等的字符串时,返回该字符串常量。如果不存在,则将字符串加入到常量池后再返回。由此可见,最终返回的都是字符串常量。所以当==比较两个都是常量池中的元素时,就会返回true。不过用intern返回的常量比较堆上字符串对象地址,仍然会是false,注意对等。下面简单举个例子:

package com.huayu.java91up;

/**
 * Create by zxb on 2017/4/18
 */
public class Test {

    public static void main(String[] args) {
        String orgin = "Hello";
        String orgin2 = "Hello";
        String token0 = "Say-Hello";
        String token1 = "Say-" + orgin;
        String token2 = "Say-" + orgin2;
        String token3 = orgin.substring(0);
        String token4 = orgin.substring(0);
        String token5 = orgin.substring(1);
        String token6 = orgin.substring(1);
        String token7 = new String("Hello");
        String token8 = new String("Say-Hello");
        System.out.println("orgin == orgin2 -> " + (orgin == orgin2));
        System.out.println("token0 == token1 -> " + (token0 == token1));
        System.out.println("token1 == token2 -> " + (token1 == token2));
        System.out.println("token3 == token4 -> " + (token3 == token4));
        System.out.println("token5 == token6 -> " + (token5 == token6));
        System.out.println("token0.intern() == token1.intern() -> " + (token0.intern() == token1.intern()));
        System.out.println("token1.equals(token2) -> " + (token1.equals(token2)));
        System.out.println("orgin == token7 -> " + (orgin == token7));
        System.out.println("token1 == token8 -> " + (token1 == token8));
        System.out.println("token0 == token8.intern() -> " + (token0 == token8.intern()));
        System.out.println("token1.intern() == token8.intern() -> " + (token1.intern() == token8.intern()));
    }
}

执行结果如下:




### Java 中 `String.intern()` 机制详解 #### 工作原理 `String.intern()` 是一种用于获取字符串常量池中对应字符串的方法。当调用此方法时,如果字符串已经存在于常量池,则返回池中的实例;否则会将当前字符串放入常量池并返回这个新的引用。 对于直接使用构造函数创建的字符串对象如 `new String("abc")` ,它会在堆上分配一个新的对象而不是优先查找常量池中存在的相同内容的对象[^1]。这意味着即使有相同的字符串值,在不同地方通过这种方式创建出来的对象也是不同的实体,它们不会共享同一份内存地址,从而可能导致不必要的重复数据以及增加垃圾收集的压力。 为了优化这种情况下的性能问题和节省内存开销,可以利用 `intern()` 方法让这些具有相等字符序列但是独立构建于堆上的字符串能够指向同一个位于永久代(PermGen space 或 Metaspace)内的唯一表示形式: ```java // 创建两个逻辑上相等但实际上不是同一个对象的字符串变量 String str1 = new String("hello"); String str2 = "hello"; System.out.println(str1 == str2); // 输出 false 表明两者并非同一对象 // 使用 intern 后再做对比 str1 = new String("hello").intern(); System.out.println(str1 == str2); // 此时输出 true 显示二者确实是指向了相同的实例 ``` 上述代码片段展示了如何借助 `intern()` 实现字符串间的高效比较及其带来的好处——减少冗余副本数量的同时提高了程序运行效率[^2]。 #### 使用场景 - **大量重复字符串处理**:在应用程序中有许多完全一致却各自占据单独空间的小型文本串时,采用 `intern()` 可有效降低总体消耗; - **哈希表键名管理**:作为 Map 结构里的 key 值时尤为适用,因为这能确保所有映射关系基于独一无二的标准参照物建立起来而不受外部因素干扰; - **配置文件解析器**:读取 XML/YAML 等格式化文档期间遇到频繁出现的关键字或属性名称亦可考虑应用此类技术手段加以简化维护成本。 需要注意的是虽然 `String.intern()` 能够带来诸多便利之处但也存在一定局限性比如可能引起 PermGen/Metaspace 溢出风险所以在实际开发过程中应当权衡利弊合理选用。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值