Java面试题:String str="a" 与 String str=new String("a") 一样吗?

本文将介绍 java 中,String str="a" 与 String str=new String("a") 一样吗,这个问题。

答案:不一样。

因为它们内存的分配方式不一样。

String str="a" 方式,JVM 会将其分配到常量池中。

String str=new String("a") 方式,JVM 会将其分配到堆内存中。

class 常量池

class 常量池可以理解为是 class 文件中的资源仓库。class 文件中除了包含类的版本、字段、方法、接口等描述信息外,还有一项信息就是常量池,用于存放编译期生成的各种字面量和符号引用。

class 的常量池主要有以下几种:

(1)class 文件常量池

(2)运行时常量池

(3)字符串常量池

(4)基本类型包装类常量池

注意,每个 class 字节码文件中都有一个常量池,里面是编译后该 class 会用到的字面量与符号引用。JVM 加载 class 时,会将其类信息,包括 class 文件常量池置于方法区中。

如何查看一个 class 文件内容?

jdk 提供了 javap 命令,用于对 class 文件进行反汇编,输出类相关信息。该命令用法如下:

用法: javap <options> <classes>
其中, 可能的选项包括:
  -help  --help  -?        输出此用法消息
  -version                 版本信息
  -v  -verbose             输出附加信息
  -l                       输出行号和本地变量表
  -public                  仅显示公共类和成员
  -protected               显示受保护的/公共类和成员
  -package                 显示程序包/受保护的/公共类和成员 (默认)
  -p  -private             显示所有类和成员
  -c                       对代码进行反汇编
  -s                       输出内部类型签名
  -sysinfo                 显示正在处理的类的系统信息 (路径, 大小, 日期, MD5 散列)
  -constants               显示最终常量
  -classpath <path>        指定查找用户类文件的位置
  -cp <path>               指定查找用户类文件的位置
  -bootclasspath <path>    覆盖引导类文件的位置

示例

Java 代码如下:

public class Demo {

    public static void main(String[] args) {
        String str1 = "abc";
        String str2 = new String("abc");
    }

}

使用 javac Demo.java 命令编译 Java 代码,生成一个字节码文件 Demo.class,然后使用 javap -v Demo.class 命令反编译字节码文件,反编译结果如下:

Classfile /D:/learn/demo_workspace/demo_java/demo_java_grammar/target/classes/Demo.class
  Last modified 2022年10月25日; size 496 bytes
  SHA-256 checksum 61d7b91a79d4077d0d1448a9d801f43205251bd0206dbc8748b97fb621bb2d3f
  Compiled from "Demo.java"
public class Demo
  minor version: 0
  major version: 52
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #5                          // Demo
  super_class: #6                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 2, attributes: 1
Constant pool: 常量池
   #1 = Methodref          #6.#23         // java/lang/Object."<init>":()V
   #2 = String             #24            // abc 常量池字符串
   #3 = Class              #25            // java/lang/String
   #4 = Methodref          #3.#26         // java/lang/String."<init>":(Ljava/lang/String;)V
   #5 = Class              #27            // Demo
   #6 = Class              #28            // java/lang/Object
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               LDemo;
  #14 = Utf8               main
  #15 = Utf8               ([Ljava/lang/String;)V
  #16 = Utf8               args
  #17 = Utf8               [Ljava/lang/String;
  #18 = Utf8               str1
  #19 = Utf8               Ljava/lang/String;
  #20 = Utf8               str2
  #21 = Utf8               SourceFile
  #22 = Utf8               Demo.java
  #23 = NameAndType        #7:#8          // "<init>":()V
  #24 = Utf8               abc
  #25 = Utf8               java/lang/String
  #26 = NameAndType        #7:#29         // "<init>":(Ljava/lang/String;)V
  #27 = Utf8               Demo
  #28 = Utf8               java/lang/Object
  #29 = Utf8               (Ljava/lang/String;)V
{
  public Demo();
    descriptor: ()V
    flags: (0x0001) 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 1: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   LDemo;
  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=3, args_size=1
         0: ldc           #2                  // String abc
         2: astore_1
         3: new           #3                  // class java/lang/String
         6: dup
         7: ldc           #2                  // String abc
         9: invokespecial #4                  // Method java/lang/String."<init>":(Ljava/lang/String;)V
        12: astore_2
        13: return
      LineNumberTable:
        line 4: 0
        line 5: 3
        line 6: 13
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      14     0  args   [Ljava/lang/String;
            3      11     1  str1   Ljava/lang/String;
           13       1     2  str2   Ljava/lang/String;
}
SourceFile: "Demo.java"

注意,其中的 “Constant pool” 就是 class 文件常量池,使用 # 加数字标记每个 “常量”。

业精于勤,荒于嬉。——韩愈《进学解》
0 不喜欢
说说我的看法 -
全部评论(
没有评论
关于
本网站属于个人的非赢利性网站,转载的文章遵循原作者的版权声明,如果原文没有版权声明,请来信告知:hxstrive@outlook.com
公众号