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

开发 后端
字符串主要用于编程,概念说明、函数解释、用法详述见正文,这里补充一点:字符串在存储上类似字符数组,所以它每一位的单个元素都是可以提取的。

[[417284]]

今天下班的路上,看到有人问这样一个问题:

图片

我看到这个问题的第一眼也有点懵。

但如果把问题换成以下代码,答案对于我来说还是非常清晰的。

  1. String str = "test" + "1"

但是当一个字符串和一个整数相加时,会创建几个对象呢?

作为老司机,深知实践是检验真理的唯一标准,动手才是硬道理。

代码清单如下:

  1. public class Hello { 
  2.   public static void main(String[] args) { 
  3.     String str = "test" + 1; 
  4.     System.out.println(str); 
  5.   } 

编译以上代码,执行,控制台输出没有任何异议。

图片

要看到创建了几个对象,我们需要反编译 Hello.class 文件,得到 java 字节码指令。

图片

看到 main 方法的字节码指令,一切已经真相大白。

其实,作为一个老司机,早就应该想到是这样的结果。

可是,面对这样一道面试题,竟然还是还是蒙圈了。

那我们来解释一下 main 方法的第一条字节码指令。

  1. 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 命令来获得。

  1. C:\Users\Thinkpad\Desktop>javap -v Hello.class 
  2. Classfile /C:/Users/Thinkpad/Desktop/Hello.class 
  3.   Last modified 2021-8-12; size 415 bytes 
  4.   MD5 checksum d350245a83d24798f2269149002970f5 
  5.   Compiled from "Hello.java" 
  6. public class Hello 
  7.   minor version: 0 
  8.   major version: 52 
  9.   flags: ACC_PUBLIC, ACC_SUPER 
  10. Constant pool: 
  11.    #1 = Methodref          #6.#15         // java/lang/Object."<init>":()V 
  12.    #2 = String             #16            // test1 
  13.    #3 = Fieldref           #17.#18        // java/lang/System.out:Ljava/io/PrintStream; 
  14.    #4 = Methodref          #19.#20        // java/io/PrintStream.println:(Ljava/lang/String;)V 
  15.    #5 = Class              #21            // Hello 
  16.    #6 = Class              #22            // java/lang/Object 
  17.    #7 = Utf8               <init> 
  18.    #8 = Utf8               ()V 
  19.    #9 = Utf8               Code 
  20.   #10 = Utf8               LineNumberTable 
  21.   #11 = Utf8               main 
  22.   #12 = Utf8               ([Ljava/lang/String;)V 
  23.   #13 = Utf8               SourceFile 
  24.   #14 = Utf8               Hello.java 
  25.   #15 = NameAndType        #7:#8          // "<init>":()V 
  26.   #16 = Utf8               test1 
  27.   #17 = Class              #23            // java/lang/System 
  28.   #18 = NameAndType        #24:#25        // out:Ljava/io/PrintStream; 
  29.   #19 = Class              #26            // java/io/PrintStream 
  30.   #20 = NameAndType        #27:#28        // println:(Ljava/lang/String;)V 
  31.   #21 = Utf8               Hello 
  32.   #22 = Utf8               java/lang/Object 
  33.   #23 = Utf8               java/lang/System 
  34.   #24 = Utf8               out 
  35.   #25 = Utf8               Ljava/io/PrintStream; 
  36.   #26 = Utf8               java/io/PrintStream 
  37.   #27 = Utf8               println 
  38.   #28 = Utf8               (Ljava/lang/String;)V 

我们看到常量池(Constant pool)的第二项是:test1。

也就是说,javac 在编译代码过程中知道:

  • 字符串 "test" 是一个字面值常量
  • 整数 1 是一个字面值常量

所以,编译器将两个常量在编译过程中,计算然后合并成一个字符串常量test1,并保存在常量池中。

所以在代码执行过程中,根本就没有创建任何对象。

本文转载自微信公众号「Golang In Memory」

 

责任编辑:姜华 来源: Golang In Memory
相关推荐

2011-07-18 13:34:44

SQL Server数拼接字符串

2020-08-12 22:03:17

JavaScript开发技术

2009-11-16 17:59:13

PHP数组转字符串

2011-06-08 15:45:41

字符串JAVA

2015-03-23 17:18:18

Java字符串问题

2011-06-03 13:03:03

JAVA

2023-04-25 15:46:51

Python字符串

2009-11-27 10:24:25

PHP字符串操作

2010-03-09 15:15:02

Python字符串类型

2010-04-30 01:17:37

unix锁

2019-01-08 09:23:16

Java字符串编码

2011-04-20 11:34:07

SQL字符串分割

2024-03-11 06:05:00

C++字符串

2011-07-22 15:38:54

SQL Server数存储过程切割字符串

2022-05-10 09:47:10

Bash字符串Linux

2022-08-14 09:01:27

代码字符串

2020-09-18 14:23:50

字符

2022-11-24 08:01:57

bash脚本字符串

2009-02-24 14:27:55

2010-01-05 10:40:07

.NET Framew
点赞
收藏

51CTO技术栈公众号