答案:不一样。
因为它们内存的分配方式不一样。
String str="a" 方式,JVM 会将其分配到常量池中。
String str=new String("a") 方式,JVM 会将其分配到堆内存中。
class 常量池可以理解为是 class 文件中的资源仓库。class 文件中除了包含类的版本、字段、方法、接口等描述信息外,还有一项信息就是常量池,用于存放编译期生成的各种字面量和符号引用。
class 的常量池主要有以下几种:
(1)class 文件常量池
(2)运行时常量池
(3)字符串常量池
(4)基本类型包装类常量池
注意,每个 class 字节码文件中都有一个常量池,里面是编译后该 class 会用到的字面量与符号引用。JVM 加载 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 文件常量池,使用 # 加数字标记每个 “常量”。