答案:不一样。
因为它们内存的分配方式不一样。
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 文件常量池,使用 # 加数字标记每个 “常量”。