Java String.intern()函数有 new string()和字面量拼接异同

intern简介

首先判断常量池中是否存在这个字符串,存在则直接返回常量池中的地址。若不存在,先把它放入常量池中,再返回该地址。
比如(”a“+“b”).intern=="ab"永远为true

举例说明

接下来用具体例子分别介绍字面量newfinal+new底层有什么不同。

1、字面量用+拼接

字符串s指向常量池中”ab“的引用,因为"a""b"都是字面量,所以编译器直接优化成s="ab"

String s="a"+"b";

2、new的方式

字符串s指向堆中”ab“对象,因为ab都是堆对象的引用,a+b本质使用Stringbuilder.append进行拼接。

String a=new String("a");
String a=new String("b");
String s=a+b;

3、final+new

由于加上final关键字,字符串s指向常量池中"ab"的引用,因为ab本质是常量,跟上面同理

final String a=new String("a");
final String a=new String("b");
String s=a+b;

经典面试题

1、对于String s=new String("a")会创建两个对象?

会创建2个对象,一个字符串常量池中“a”对象,一个是堆中的"a’对象

2、对于String s=new String("a")+new String("b")又会创建几个对象?

答案:会创建6个对象!
原理:上一题分析可知new String(“a”)产生2个对象,同理new String(“a”)也产生2个对象,由于+号两边只要有变量,就会使用产生一个stringbuilder对象,最终builder转为String调用toString方法,本质是new String(“ab”)再产生一个对象。

jdk7之后的intern原理变化

jdk7后会让常量池指向堆的引用,节省空间。而jdk1.6是直接把堆中的对象拷贝一份。

在这里插入图片描述

最佳实践

下面再用几个例子加深对intern函数的理解。

    @Test
    public void test4() {
        String s3=new String("a")+new String("a");
        s3.intern(); // 常量池中创建aa,并指向堆中的s3
        String s4="aa";
        System.out.println(s3==s4); // jdk78 true

        String s5=new String("b"); // 堆
        String s6="b"; // 常量池
        String s7=s5.intern(); // 常量池
        System.out.println(s5);
        System.out.println(s5==s6); // false
        System.out.println(s5==s7); // false
        System.out.println(s6==s7); // true
    }

    @Test
    public void test3() {
        String str1=new String("hello"+"world");
        String intern = str1.intern(); // 返回常量池地址,但该地址是指向堆中的str1
        String str2="helloworld"; // 返回常量池地址
        System.out.println(str1==intern); // false
        System.out.println(str2==intern); // true
    }

    @Test
    public void test2() {
        String str1=new String("hello"+"world"); // 堆 同时在方法区常量池生成helloworld,都是常量不会使用stringBuilder
        String str1_intern=str1.intern(); // 常量池 直接返回常量池中的helloworld,因为上一个语句已将helloworld放入常量池
        String str2="hello"+"world"; // 常量池
        String word="word";
        String str3=new String("hello"+word); // 堆 有一个是变量就是用builder,因为编译时不知道变量的具体值
        System.out.println(str1==str2); // false 因为str1指向堆,str2指向常量池
        System.out.println(str1==str1_intern); // false str1_intern返回的常量池的地址
        System.out.println(str2==str1_intern); // true
        System.out.println(str1==str3); // false 两个是不同的普通的堆对象
    }

    @Test
    public void test1(){
        String str1="hello"; // 指向常量池
        String str2=new String("hello"); // 指向堆中的地址,但实际引用的是堆中的字符串常量池地址
        String str3=str2.intern(); // 指向常量池
        System.out.println(str1==str2); // false
        System.out.println(str1==str3); // true
        System.out.println(str2==str3); // false
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值