Java中String.intern()方法浅记

Java中String.intern()方法浅记

String在Java中是一个比较特殊的存在。String既可以使用字面量进行赋值,也可以使用new进行赋值。

  • 使用字面量进行赋值,会直接放进字符串常量池
  • 如果使用new进行创建对象,会在堆中生辰给一个对象,也会在常量池中存放一份,两者并不相同。

注意:

字符串常量池从jdk7开始,从方法区移到了堆中。静态变量也从方法区中移到了堆中。

概念

使用intern()方法,会先判断字符串常量池中是否已经包含当前的字符串,如果没有的话,则会在字符串常量池中存放一份。在具体的实现中稍有不同。

  • 在jdk6之前(包含jdk6),字符串常量池在方法区中,与堆不在同一个区域,所以字符串常量池中是拷贝了一份字符串的对象,Java堆中的String对象和字符串常量池的String对象不是同一个。
  • 在jdk7之后(包含jdk7),字符串常量池转移到了堆中。当堆中有一个String对象的时候,在调用intern方法时,如果字符串常量池没有这个字符串,则会存放堆中String对象的地址引用,不会像jdk7之前的拷贝一份到字符串常量池中。此时,字符串常量池翠芳的和堆中String对象代表的是一个。

如果有描述不清处的欢迎大家查看《深入了解java虚拟机的》第三版的63页。字符串常量池的迁移查看46页。

代码验证

**环境:**jdk1.8

主要验证的是jdk8,也就是字符串常量池迁移到堆的情况,jdk6之前的情况,感兴趣的可以自己尝试。

测试方法:

第一种情况:

public class InternTest {
    public static void main(String[] args) {
        String str1 = new String("jay,cay");//会在堆中有一个,在字符串常量池中有一个
        str1.intern();//此时这行代码不会往字符串常量池中存放,因为字符串常量池中已经有一个相同值的对象
        String str2 = "jay,cay";
        System.out.println(str1 == str2);
    }
}

测试结果:

false

分析:

在new的时候会在堆中有一个,在字符串常量池中有一个。所以intern方法相当于没有起作用,因为因为字符串常量池中已经有一个相同值的对象

第二种情况:

public class InternTest {
    public static void main(String[] args) {
        String str1 = new String("jay,cay");
        str1.intern();
        String str2 = "jay,cay";
        System.out.println(str1 == str2);

        String str3 = new String("aa") + new String("bb");//字符串常量池中不会有aabb
        str3.intern();//将堆中的aabb的引用存放在字符串常量池中
        String str4 = "aabb";
        System.out.println(str3 == str4);
    }
}

测试结果:

false
true

分析:

由于两个new字符串的拼接,所以在字符串长量池中不会有aabb,下面的intern方法会将堆中的aabb的引用存放在字符串常量池中。这样str3和str4就相同了。

反思:

实际中使用的StringBuilder产生的字符串不在字符串常量池中的多,下面这段代码可以在《深入了解Java虚拟》63页找到。

String str5 = new StringBuilder("计算机").append("软件").toString();
str5.intern();
String str6 = "计算机软件";
System.out.println(str5 == str6);//得到的也是true

特例:

在《深入了解Java虚拟》63页提到了一个特例,就是java这个字符串,使用下面的方式得到的是false,原因是在项目启动的时候默认会加载一个java字符串在字符串常量池。

String str7 = new StringBuilder("ja").append("va").toString();
str5.intern();
String str8 = "java";
System.out.println(str7 == str8);//得到是false

疑惑:待解决

发现测试单元中的10, 11, 12是特例,大家可以试试。初步猜测和上面 “java” 字符串一样,在使用测试单元的,会提前加载10, 11, 12这三个字符串在字符串常量池。

测试方法代码如下:

@ExtendWith(SpringExtension.class)
@SpringBootTest
public class InternTest {
    @Test
    public void testIntern(){
    	//String str3 = new String("1") + new String("2");
    	//10,11,12这三个比较特殊
        String str3 = new String("1") + new String("1");
        str3.intern();
        //String str4 = "12";
        String str4 = "11";
        System.out.println(str3 == str4);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值