一个关于Java字符串对象问题的详细解答

发表于:2021-9-13 09:28

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:fooree    来源:Golang In Memory

#
Java
分享:
  今天下班的路上,看到有人问这样一个问题:
  我看到这个问题的第一眼也有点懵。
  但如果把问题换成以下代码,答案对于我来说还是非常清晰的。
  String str = "test" + "1"; 
  但是当一个字符串和一个整数相加时,会创建几个对象呢?
  作为老司机,深知实践是检验真理的唯一标准,动手才是硬道理。
  代码清单如下:
  public class Hello { 
    public static void main(String[] args) { 
      String str = "test" + 1; 
      System.out.println(str); 
    } 
  } 
  编译以上代码,执行,控制台输出没有任何异议。
  要看到创建了几个对象,我们需要反编译 Hello.class 文件,得到 java 字节码指令。
  看到 main 方法的字节码指令,一切已经真相大白。其实,作为一个老司机,早就应该想到是这样的结果。可是,面对这样一道面试题,竟然还是还是蒙圈了。那我们来解释一下 main 方法的第一条字节码指令。
  0: ldc       
  ldc 的意思是 LoaD Constant,即从常量池中加载一个常量并压入(push)到操作数栈(operand stack)。
  #2 是常量池中索引,表示常量池中的第2项。
  关于 ldc 字节码指令的详细说明,请参考官方文档,连接地址为:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.ldc。
  常量池中的第2个常量到底是什么,我们还需要使用 javap 命令来获得。
  C:\Users\Thinkpad\Desktop>javap -v Hello.class 
  Classfile /C:/Users/Thinkpad/Desktop/Hello.class 
    Last modified 2021-8-12; size 415 bytes 
    MD5 checksum d350245a83d24798f2269149002970f5 
    Compiled from "Hello.java" 
  public class Hello 
    minor version: 0 
    major version: 52 
    flags: ACC_PUBLIC, ACC_SUPER 
  Constant pool: 
     #1 = Methodref          #6.#15         // java/lang/Object."<init>":()V 
     #2 = String             #16            // test1 
     #3 = Fieldref           #17.#18        // java/lang/System.out:Ljava/io/PrintStream; 
     #4 = Methodref          #19.#20        // java/io/PrintStream.println:(Ljava/lang/String;)V 
     #5 = Class              #21            // Hello 
     #6 = Class              #22            // 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               Hello.java 
    #15 = NameAndType        #7:#8          // "<init>":()V 
    #16 = Utf8               test1 
    #17 = Class              #23            // java/lang/System 
    #18 = NameAndType        #24:#25        // out:Ljava/io/PrintStream; 
    #19 = Class              #26            // java/io/PrintStream 
    #20 = NameAndType        #27:#28        // println:(Ljava/lang/String;)V 
    #21 = Utf8               Hello 
    #22 = Utf8               java/lang/Object 
    #23 = Utf8               java/lang/System 
    #24 = Utf8               out 
    #25 = Utf8               Ljava/io/PrintStream; 
    #26 = Utf8               java/io/PrintStream 
    #27 = Utf8               println 
    #28 = Utf8               (Ljava/lang/String;)V 
  我们看到常量池(Constant pool)的第二项是:test1。
  也就是说,javac 在编译代码过程中知道:
  · 字符串 "test" 是一个字面值常量
  · 整数 1 是一个字面值常量
  所以,编译器将两个常量在编译过程中,计算然后合并成一个字符串常量test1,并保存在常量池中。
  所以在代码执行过程中,根本就没有创建任何对象。

  本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号