概要
Java 工程师面试官偏爱的问题之一,就是 ”abc” 和 new String(“abc”) 的区别是什么?回答的比较好的会带出 Java 堆,栈,常量池,引用等概念。但今天不止如此,我们从指令的角度,去看这个问题。
正文
我们知道,java 类编译后的字节码是个二进制文件,不是给人而是给机器阅读的。但是 java 有一个 javap 的指令,可以把字节码翻译成人类能看懂的东西。
javap 是 Java class 文件分解器,可以反编译(即对 javac 编译的文件进行反编译),也可以查看 java 编译器生成的字节码。用于分解 class 文件。
现在有一个类,定义入下
public class A01 {
public static void main(String … args){
String a = “123”;
String c = new String(“123”);
}
}
先用 javac A01.java 编译成字节码,再使用 javap -c A01.class 进行反编译。得到入下文本
Compiled from “A01.java”
public class javap.A01 {
public javap.A01();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object.”<init>”:()V
4: return
public static void main(java.lang.String…);
Code:
0: ldc #2 // String 123
2: astore_1
3: new #3 // class java/lang/String
6: dup
7: ldc #2 // String 123
9: invokespecial #4 // Method java/lang/String.”<init>”:(Ljava/lang/String;)V
12: astore_2
13: return
}
我们主要看下面这段关于 main 方法的文本,里面涉及的指令不多,我整理了一下
ldc: 将常亮加载到操作数栈 astore_1: 将栈顶元素的值保存到变量 1new: 为要创建的类实例开辟内存空间,并将地址压入操作数栈 dup: 复制操作数栈顶值,并将其压入栈顶 invokespecial: 调用方法,例子中的方法是类的构造器
现在我们结合指令和操作数栈,来模拟一次计算
回到最开始的问题,a=”123″ 和 a =new String(“123”) 的区别,前者指向的是常量池的地址,后者指向的是堆中新开辟的地址。这两个 == 的结果,自然是不相等的。equals 的结果呢?equals 是字符逐个比较内容,是相等的。