String相关经典面试题

一、JVM 常量池中存储的是对象还是引用呢

答:String类型存放的是对象的引用
当字符串不存在的时候,会在堆中创建字符串对象,然后再在字符串常量池当中创建这个引用(常量池指向堆中的字符串)。

在这里插入图片描述
参考链接:JVM 常量池中存储的是对象还是引用呢?
摘录:如果您说的确实是runtime constant pool(而不是interned string pool / StringTable之类的其他东西)的话,其中的引用类型常量(例如CONSTANT_String、CONSTANT_Class、CONSTANT_MethodHandle、CONSTANT_MethodType之类)都存的是引用,实际的对象还是存在Java heap上的。

二、字符串拼接

String 类型的变量和常量做“+”运算时发生了什么?
注意:用 == 比较的时候,比较的是地址值是否相等,可以理解为判断是否指向了同一个对象。

三、String#intern 方法有什么作用

String.intern() 是一个 native(本地)方法,其作用是将指定的字符串对象的引用保存在字符串常量池中,可以简单分为两种情况:

  • 如果字符串常量池中保存了对应的字符串对象的引用,就直接返回该引用
  • 如果字符串常量池中没有保存了对应的字符串对象的引用,那就在常量池中创建一个指向该字符串对象的引用并返回。(不会再新建一个字符串对象了)

四、创建对象个数

1.String str = “abc”;这句话创建了几个字符串对象?

答:0个或1个对象。
创建字符串“abc"时会先在字符串池中查找,看是否有相等的对象引用,没有的话就在堆中创建“abc”字符串对象,同时把地址驻留在字符串池,这个时候会创建一个对象;有的话则直接赋值为常量池中的引用,避免重复创建字符串对象,这个时候会创建0个对象。

在这里插入图片描述

2. String str = “ab”+“c”;这句话创建了几个字符串对象?

答:同上,0个或1个对象,JVM会将字符串常量的拼接优化成最终结果”abc“

3. String str = new String(“abc”);这句话创建了几个字符串对象?

答:创建一个或者两个对象。
(1)我们可以把上面这行代码分成String str、=、"abc"和new String()四部分来看待;
(2)String str只是定义了一个名为str的String类型的变量,因此它并没有创建对象;
(3)=是对变量str进行初始化,将某个对象的引用(或者叫地址)赋值给它,显然也没有创建对象;
(4)new String(“abc”)可以被看成"abc"和new String()

  • 创建字符串“abc"时会先在字符串池中查找,看是否有相等的对象引用,没有的话就在堆中创建“abc”字符串对象,同时把地址驻留在字符串池,相当于新建一个字符串对象;有的话则直接用常量池中的引用,避免重复创建字符串对象,相当于创建0个字符串对象。
  • 通过构造函数new String(“abc”)在堆内存中创建的新字符串对象。
  • 注:第一步为什么要新增一个“abc”呢,是因为享元模式,保证后续的重复利用。

在这里插入图片描述

4. String str = new String(“ab”) + “c”;这句话创建了几个字符串对象?

答:最少两个(new String()新建的、最后拼接生成的),最多四个。

在这里插入图片描述
:为什么new StringBuilder().toString() 内层的new String(value, 0, count);方法不会再多新建一个对象?因为此时并不是双引号的字符串,不是字符串字面量。所以不会再新建一个对象,不会被主动推送到常量池中。
为什么new String(“abc”)会新建abc对象?因为new String()里面是双引号,所以会新建对象。

五、有关intern()用法的地址是否相等

1. jdk7之后的环境中,以下代码,输出结果是什么

		String str5 = new String("1")+new String("1");
        String str7 = str5.intern();
        String str6 = "11";
        System.out.println(str5 == str6); //true
        System.out.println(str7 == str6); //true

在这里插入图片描述

(1)创建字符串“1"时会先在字符串池中查找,看是否有相等的对象引用,没有的话就在堆中创建“1”字符串对象,同时把地址驻留在字符串池。
(2)new String(“1”)创建了两个对象。
(3)new String(“1”)+new String(“1”);会调用StringBuilder的append()方法,将字符串“11”存放在堆中。
(4)str5.intern();会查找常量池中是否有“11”字符串的引用,如果有的话则直接返回该引用,没有的话常量池中创建一个指向该字符串对象的引用并返回。假设目前是没有的,所以会在字符串常量池中创建一个引用指向堆中已存在的(也就是该字符串对象str5)字符串“11”,并将这个引用赋值给str7,注意此时str5的指向是不变的。
(5)String str6 = “11”;因为现在字符串“11”已经存在在常量池中,所以str6会赋值为常量池中的引用。
(6)因为str5,str6,str7都赋值为字符串常量池中的引用(指向堆中的“11”),所以结果输出为true。

2. jdk7之后的环境中,以下代码,输出结果是什么

		String str5 = new String("1")+new String("1");
		String str6 = "11";
        String str7 = str5.intern();
        System.out.println(str5 == str6); //false
        System.out.println(str7 == str6); //true

在这里插入图片描述
和4.1的内容相比只是intern()的赋值顺序发生了改变。
(1)创建字符串“1"时会先在字符串池中查找,看是否有相等的对象引用,没有的话就在堆中创建“1”字符串对象,同时把地址驻留在字符串池。
(2)new String(“1”)创建了两个对象。
(3)new String(“1”)+new String(“1”);会调用StringBuilder的append()方法,将字符串“11”存放在堆中。
(4)String str6 = “11”;假设此时字符串“11”不在常量池中,所以会在堆中新建一个字符串对象“11"并且在常量池中存放该引用。
(5)String str7 = str5.intern();字符串常量池中保存了对应的字符串对象的引用,就直接返回字符串11的引用。此时str5的指向是不变的,还是指向堆中的对象。
(6)所以,str5和str6的地址值不同,str7和str6的地址值相同。

六、参考资料

  1. 几张图轻松理解String.intern()
  2. 专题整理之—String的字符串常量池
  3. 流程图详解 new String(“abc”) 创建了几个字符串对象
  4. 如何理解 String 类型值的不可变?
  • 17
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值