深入经典面试题:new String(“123“) 创建了几个String对象

经典面试题 String str = new String(“hello world”);创建了几个对象。

学习 java 准备面试,不能光背面试题的答案,更要深入面试题,了解面试题背后的java基础。

那么让我们来看一下 String str = new String("hello world");这段代码到底涉及到了多少 java 基础。

我知道的创建 String 对象的方式共有五种。

  1. new String(char[ ])

    通过 char 数组创建 String 对象

  2. new String(byte[ ])

    通过 byte 数组创建 String 对象。因为 JDK1.8 中,String 中的数据是由 char[ ]存储的,当通过 byte 数组创建 String 对象时,需要将 byte 数组转换为 char 数组。由于 byte 是一个字节,而 char 是两个字节,而且 byte 的数据范围包含负数。所以两个数组相互转换时,如果不指定编码方式,可能会导致乱码 (java 中 char 为 unicode 编码,而以 byte[ ] 形式创建 String 对象通常是网络请求或者IO读入时使用的,包含多种编码方式),以及 byte 数组前后不一致的错误。

    String str = new String(new byte[]{-24,97,98,99});
    System.out.println(str);
    for (byte aByte : str.getBytes()) {
        System.out.print(aByte + " ");
    }
    
    //output
    �abc
    -17 -65 -67 97 98 99 !!前后 byte 数组不一致
    

    需要指定编码方式例如:

    String str = new String(new byte[]{-24,97,98,99},"ISO-8859-1");
    System.out.println(str);
    for (byte aByte : str.getBytes("ISO-8859-1")) {
        System.out.print(aByte + " ");
    }
    
    //output
    èabc
    -24 97 98 99 
    
  3. new String(int[ ])

  4. String str = "123"; 最常用的字面量形式创建String对象

  5. String str = new String("123");

本节只涉及 4、5 两种创建 String 对象的方式。

1.字面量形式创建

String str = "123";我们称 123 为字面量,当你点击编译软件的运行按钮,当前 .java 文件会被编译为 .class 字节码文件。字面量 123 存在于 class 文件的常量池中。其中,常量池中会存在两个与 123 相关的常量。

  1. CONSTANT_Utf8_info 就是 123
  2. CONSTANT_String_info 存储 CONSTANT_Utf8_info 的索引

当这个类被加载时,常量池会被加载进入运行时常量池,以上两个常量的类型会发生变化。

  1. CONSTANT_Utf8_info -> Symbol* ,指针指向 C++ 类型的 Symbol 对象,symbol 对象的值就是 123
  2. CONSTANT_String_info -> JVM_CONSTANT_UnresolveString_info(未被解析的 String 引用)

在加载阶段不会产生 String 对象。直到解析阶段才会创建 String 对象。当虚拟机运行到 ldc 等操作符号引用的字节码指令时,会触发这个类的解析阶段,将符号引用替换为直接引用。而此时 JVM_CONSTANT_UnresolveString_info 也就会被 resolve 为真正的 String 对象的引用。当然此时需要在堆中创建内容为 123 的 String 对象,但也不是傻傻的创建对象。创建时会先去判断字符串常量池中是否有内容一样也是 123 的对象的引用。如果有则不需要创建新的 String 对象。

至此,第四种创建 String 的方式讲解完成,至于创建时如何判断,以及如何向字符串常量池中添加新的数据,涉及到字符串常量池的实现原理 StringTable,笔者能力不够,暂不讲解。有兴趣的老铁可以去阅读 StringTable 源码(查询方法 StringTable::lockup(),添加方法 StringTable::basic_add() )。

总结:通过字面量形式创建 String 对象,对象会在类的解析阶段被创建,并且相同内容的对象只有一个。如果创建时已经存在重复的,则不会创建新的 String 对象。

2.有参构造创建 String 对象

String str = new String("123"); 同样, 123 是字面量,在类的解析阶段会创建 String 对象。与第四种创建方式不同的地方是,使用了 String 的有参构造。

当使用构造方法创建 String 对象,不光会在类加载过程中创建,还会在程序运行时在堆中创建 String 对象。并且这个对象是野生的,不归字符串常量池管。

只有在类加载过程中产生的 String 对象,以及运行时通过调用 String::intern() 方法把 String 的监护权给字符串常量池的 String 对象,才归字符串常量池管。不太懂?那反过来想,如果所有 String 对象都归字符串常量池管的话,在程序运行期间,可能会出现无数个 String,那字符串常量池早就炸了。不然为什么叫字符串常量池,而不叫字符串池。

3.总结

这个面试题,涉及到的 java 基础

  1. String 的几种创建形式
  2. .class 文件的常量池
  3. 类的加载阶段会将 class 文件中的常量池加载进入运行时常量池中,并且改变常量的结构
  4. ldc 等操作符号引用的字节码指令会触发类的解析阶段
  5. 类的解析阶段会将符号引用替换为直接引用,本文涉及到 String 对象的创建
  6. 字符串常量池
  7. new String("123"); 会在运行时在堆中创建 String 对象,这个对象是野生的不归字符串常量池管理

想更了解字符串常量池的同学,可以看我上一篇博客,深入Java基础——字符串常量池,感谢捧场。

如果发现本文有错误请直接指出,感谢。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值