new String()到底创建了几个对象?

背景

在学习 《阿里巴巴Java开发手册》详解/24 代码调试的正确姿势时,无意间发现了一个在秋招面试经常会被问的问题 :

当你通过new String(“test”)时,到底会创建几个对象,是否会放入常量池?

答案
  • 在执行这行代码前,没有字面量test字符串出现,则会创建两个实例对象, 一个在堆中,一个在常量池中
  • 否则只会在堆中创建一个实例对象

分析

代码.V1:

public class App 
{
    public static void main( String[] args )
    {
        String a = new String("testString");
        System.out.println(a);
    }
}

将代码反汇编得到:

 0 new #2 <java/lang/String>		    //创建String对象
 3 dup									//将刚栈顶的reference复制压栈
 4 ldc #3 <testString>					//将常量池中的“testString”对象的reference压栈
 6 invokespecial #4 <java/lang/String.<init>> //初始化String对象
 9 astore_1							
10 getstatic #5 <java/lang/System.out>
13 aload_1
14 invokevirtual #6 <java/io/PrintStream.println>
17 return

指令解释:

  • new指令完成了实例对象的内存分配,初始化零值,对象头设置等操作,从jvm视角完成了一个对象的创建操作,并将reference压栈
  • dup指令将栈顶数值复制并压栈。jvm这样的做的目的是为了效率考虑,减少一次aload操作,用dup来代替。
  • ldc是将常量池中的常量值推入栈顶,也就是将testString对象的reference值压栈
  • invokespecial指令才是从java代码的角度去完成对象的创建,将对象按我们的意愿去初始化

代码.V1总结:
代码中的字面量都会在编译期间被放入.class文件的静态常量池中。当执行 new String(“testString”)时,会加载运行时常量池中的对象引用值,然后通过<init>方法来完成初始化,得到新的对象。

代码.V2

public class App 
{
    public static void main( String[] args )
    {
        String a = "testString";
        System.out.println(a);
    }
}

反汇编

 0 ldc #2 <testString>
 2 astore_1
 3 getstatic #3 <java/lang/System.out>
 6 aload_1
 7 invokevirtual #4 <java/io/PrintStream.println>
10 return

代码.V2总结
具体指令就不解释了,可以对比V1的反汇编指令。
可以看出V2中直接就是加载了常量池中的testString对象的引用,然后存储到本地变量a中,本质上是没有创建新的String对象,只是创建了一个本地引用变量来接收实例对象的引用值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值