前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >面试官问他Java中“a”+“b”究竟会产生几个对象?

面试官问他Java中“a”+“b”究竟会产生几个对象?

作者头像
ImportSource
发布2018-07-25 17:13:13
4710
发布2018-07-25 17:13:13
举报
文章被收录于专栏:ImportSourceImportSource

最近在群里聊起这个话题。

有人在群里提问说“刚才面试官问他:‘Java中“a”+“b”究竟会产生几个对象?’”。

群里的各路豪杰就开始了一波波的解答。其实这也是一个老生常谈的问题。

今天我们就试图对这个问题进行一次剖析。

首先我们新建一个类AB1.java,如下:

public class AB1 {
    String str="a"+"b";
}

然后编译此类javac AB1.java,得到AB1.class文件。

通过idea把class文件打开,发现“a”+“b”被合并到一块了。可以看出反编译器是直接从class文件中取到了“ab”,而不是“a”+“b”。

也就是说,我们在javac编译此类的时候,编译器已经智能的把“a”+“b”合并为了“ab”,这算是编译器优化。

"a"+“b”

上面只是表象,现在我们通过javap -v AB1.class看看具体的字节码指令:

hezhuofandeMacBook-Pro:datastructure hezhuofan$ javap -v AB1.class Classfile /Users/hezhuofan/Documents/importsource_dev/concurrency-samples/src/main/java/com/importsource/datastructure/AB1.class Last modified Apr 25, 2018; size 274 bytes MD5 checksum 76e8f9d06c49826518eed49957bcf526 Compiled from "AB1.java" public class com.importsource.datastructure.AB1 minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #5.#14 // java/lang/Object."<init>":()V #2 = String #15 // ab #3 = Fieldref #4.#16 // com/importsource/datastructure/AB1.str:Ljava/lang/String; #4 = Class #17 // com/importsource/datastructure/AB1 #5 = Class #18 // java/lang/Object #6 = Utf8 str #7 = Utf8 Ljava/lang/String; #8 = Utf8 <init> #9 = Utf8 ()V #10 = Utf8 Code #11 = Utf8 LineNumberTable #12 = Utf8 SourceFile #13 = Utf8 AB1.java #14 = NameAndType #8:#9 // "<init>":()V #15 = Utf8 ab #16 = NameAndType #6:#7 // str:Ljava/lang/String; #17 = Utf8 com/importsource/datastructure/AB1 #18 = Utf8 java/lang/Object { java.lang.String str; descriptor: Ljava/lang/String; flags: public com.importsource.datastructure.AB1(); descriptor: ()V flags: ACC_PUBLIC Code: stack=2, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: aload_0 5: ldc #2 // String ab 7: putfield #3 // Field str:Ljava/lang/String; 10: return LineNumberTable: line 6: 0 line 7: 4 } SourceFile: "AB1.java"

但是如果我们换成如下,情况就会改变。

a+b

现在我们新建一个AB.java:

public class AB {
    String a = "a";
    String b = "b";
    String result = a + b ;
}

然后我们javac AB.java生成class,然后使用idea打开AB.class:

发现result的a+b被移动到了构造函数里。

然后用javap -v AB.class来来细节:

hezhuofandeMacBook-Pro:datastructure hezhuofan$ javap -v AB.class Classfile /Users/hezhuofan/Documents/importsource_dev/concurrency-samples/src/main/java/com/importsource/datastructure/AB.class Last modified Apr 25, 2018; size 504 bytes MD5 checksum fa64cc63e24478ad1026aec48ed45243 Compiled from "AB.java" public class com.importsource.datastructure.AB minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #12.#23 // java/lang/Object."<init>":()V #2 = String #13 // a #3 = Fieldref #11.#24 // com/importsource/datastructure/AB.a:Ljava/lang/String; #4 = String #15 // b #5 = Fieldref #11.#25 // com/importsource/datastructure/AB.b:Ljava/lang/String; #6 = Class #26 // java/lang/StringBuilder #7 = Methodref #6.#23 // java/lang/StringBuilder."<init>":()V #8 = Methodref #6.#27 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; #9 = Methodref #6.#28 // java/lang/StringBuilder.toString:()Ljava/lang/String; #10 = Fieldref #11.#29 // com/importsource/datastructure/AB.result:Ljava/lang/String; #11 = Class #30 // com/importsource/datastructure/AB #12 = Class #31 // java/lang/Object #13 = Utf8 a #14 = Utf8 Ljava/lang/String; #15 = Utf8 b #16 = Utf8 result #17 = Utf8 <init> #18 = Utf8 ()V #19 = Utf8 Code #20 = Utf8 LineNumberTable #21 = Utf8 SourceFile #22 = Utf8 AB.java #23 = NameAndType #17:#18 // "<init>":()V #24 = NameAndType #13:#14 // a:Ljava/lang/String; #25 = NameAndType #15:#14 // b:Ljava/lang/String; #26 = Utf8 java/lang/StringBuilder #27 = NameAndType #32:#33 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder; #28 = NameAndType #34:#35 // toString:()Ljava/lang/String; #29 = NameAndType #16:#14 // result:Ljava/lang/String; #30 = Utf8 com/importsource/datastructure/AB #31 = Utf8 java/lang/Object #32 = Utf8 append #33 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder; #34 = Utf8 toString #35 = Utf8 ()Ljava/lang/String; { java.lang.String a; descriptor: Ljava/lang/String; flags: java.lang.String b; descriptor: Ljava/lang/String; flags: java.lang.String result; descriptor: Ljava/lang/String; flags: public com.importsource.datastructure.AB(); descriptor: ()V flags: ACC_PUBLIC Code: stack=3, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: aload_0 5: ldc #2 // String a 7: putfield #3 // Field a:Ljava/lang/String; 10: aload_0 11: ldc #4 // String b 13: putfield #5 // Field b:Ljava/lang/String; 16: aload_0 17: new #6 // class java/lang/StringBuilder 20: dup 21: invokespecial #7 // Method java/lang/StringBuilder."<init>":()V 24: aload_0 25: getfield #3 // Field a:Ljava/lang/String; 28: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 31: aload_0 32: getfield #5 // Field b:Ljava/lang/String; 35: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 38: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 41: putfield #10 // Field result:Ljava/lang/String; 44: return LineNumberTable: line 6: 0 line 7: 4 line 8: 10 line 9: 16 } SourceFile: "AB.java"

你会发现在这种情况下,StringBuilder介入了,它负责把a+b给拼接起来。

也就是等价于

StringBuilder sb=new StringBuilder(); sb.append(a); sb.append(b); result=sb.toString();

上面画的黑体的指令就是这段代码。

new String("ab")

那么new String("ab")呢?

代码:

public class ABNew {
    public static void main(String[] args) {
         String str=new String("ab");
    }
}

依然是通过javac编译后,通过javap -v ABNEW.class来查看:

hezhuofandeMacBook-Pro:datastructure hezhuofan$ javap -v ABNew.class Classfile /Users/hezhuofan/Documents/importsource_dev/concurrency-samples/src/main/java/com/importsource/datastructure/ABNew.class Last modified Apr 26, 2018; size 364 bytes MD5 checksum 224e8d6e5f5b8bd353f6ff043b198d67 Compiled from "ABNew.java" public class com.importsource.datastructure.ABNew minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #6.#15 // java/lang/Object."<init>":()V #2 = Class #16 // java/lang/String #3 = String #17 // ab #4 = Methodref #2.#18 // java/lang/String."<init>":(Ljava/lang/String;)V #5 = Class #19 // com/importsource/datastructure/ABNew #6 = Class #20 // java/lang/Object #7 = Utf8 <init> #8 = Utf8 ()V #9 = Utf8 Code #10 = Utf8 LineNumberTable #11 = Utf8 main #12 = Utf8 ([Ljava/lang/String;)V #13 = Utf8 SourceFile #14 = Utf8 ABNew.java #15 = NameAndType #7:#8 // "<init>":()V #16 = Utf8 java/lang/String #17 = Utf8 ab #18 = NameAndType #7:#21 // "<init>":(Ljava/lang/String;)V #19 = Utf8 com/importsource/datastructure/ABNew #20 = Utf8 java/lang/Object #21 = Utf8 (Ljava/lang/String;)V { public com.importsource.datastructure.ABNew(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 6: 0 public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=3, locals=2, args_size=1 0: new #2 // class java/lang/String 3: dup 4: ldc #3 // String ab 6: invokespecial #4 // Method java/lang/String."<init>":(Ljava/lang/String;)V 9: astore_1 10: return LineNumberTable: line 8: 0 line 9: 10 } SourceFile: "ABNew.java"

可以发现,“ab”是在常量池中,new String()这个动作触发new指令强制新建了一个对象。所以是创建了两个对象。这一点也可以从下面的代码中得到验证:

System.out.println("ab"==str);//false

总结

当“a”+“b”时,在javac编译阶段就会被优化成“ab”存储常量池。当是a+b时,会使用StringBuilder进行拼接。new String时,则会额外强制新建一个对象。

所以第一种情况下只会有一个对象,就是str;第二种情况下是三个对象 a、b、result,同时创建了StringBuilder一个对象,所以一共是四个对象。第三种情况new String时,则是两个对象。

ps:本文所在环境Java8。另有误的地方望指正。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-04-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 ImportSource 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档