字符串对象和字符串常量
先看一段代码的执行结果:
public class StringTest {
@Test
public void test(){
String str1 = "1";
String str2 = new String(new char[]{'1'});
String str3 = new String(new char[]{'1'});
System.out.println("String str1 = \"1\";");
System.out.println("String str2 = new String(new char[]{'1'});");
System.out.println("String str3 = new String(new char[]{'1'});");
System.out.println();
System.out.println( "str1 == str2: " + (str1 == str2));
System.out.println( "str2 == str3: " + (str2 == str3));
System.out.println( "str1 == \"1\": " + (str1 == "1"));
System.out.println( "str2 == \"1\": " + (str2 == "1"));
System.out.println( "str1 == str1.intren(): " + (str1 == str1.intern()));
System.out.println( "str1 == str2.intren(): " + (str1 == str2.intern()));
}
}
执行结果:
String str1 = "1";
String str2 = new String(new char[]{'1'});
String str3 = new String(new char[]{'1'});
str1 == str2: false
str2 == str3: false
str1 == "1": true
str2 == "1": false
str1 == str1.intren(): true
str1 == str2.intren(): true
理解上面的执行结果:
code | 说明 |
---|---|
str1 | 指向字符常量"1", |
str2、str3 | 分别指向两个通过字符数组[‘1’]创建字符对象 |
str1 == str2: false | str1指向的“1”是在JVM内存的常量池区域,str2是一个在堆区的对象,所以不是同一个对象 |
str2 == str3: false | str2、str3是在堆区两个不同对象,地址也不一样,所以返回false |
str1 == “1”: true,str2 == “1”: false | 代码中所有常量"1"都是指向JVM常量池同一份,所以它们的地址是一样的 |
str1 == str1.intren(): true,str1 == str2.intren(): true, intren() | 字符对象在常量池中的对象,所以跟"1"是同一个地址 |
通过字节码认识字符串常量和字符串对象的区别
Java源码:
public void test2(){
String str1 = "1";
String str2 = new String(new char[]{'1'});
}
通过JDK自带的工具进行反汇编:
javap -c -s StringTest.class
反汇编结果:
public void test2();
descriptor: ()V
Code:
0: ldc #2 // String 1
2: astore_1
3: new #3 // class java/lang/String
6: dup
7: iconst_1
8: newarray char
10: dup
11: iconst_0
12: bipush 49
14: castore
15: invokespecial #4 // Method java/lang/String."<init>":([C)V
18: astore_2
19: return
汇编代码中 0-2的汇编指令对应源码 String str1 = “1”,ldc命名从常量池中加载常量,astore1将栈顶内容保存到调用栈本地变量1;
汇编代码中 3-18的汇编指令对应源码 String str2 = new String(new char[]{‘1’}),是通过new命名创建一个String对象。