public class StringDemo {
public static void main(String[] args) {
String a = "hello ";
String b = a + "world";
String c = "hello " + "world";
String d = "hello world";
System.out.println(b == d); //false
System.out.println(c == d); //true
}
}
按照我的理解,直接对一个String对象赋值时,会将该值当作匿名对象保存到对象池(String b = a + "world";),
之后还有其他String对象也赋同样的值时(String c = "hello " + "world"; String d = "hello world";),
不会开辟新的内存空间,而是使用已有的对象进行引用的分配(b, c, d 都指向对象池中的同一块地址)。
但是实际效果是: c、d指向同一块内存,b指向另一块内存。
请问其中原理是什么?
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。
Java的运行时数据区中,有一个方法区(Method Area)和堆(Heap)。
对于那些在编译时就能确定的字面量都会存放在运行时常量池中,而常量池是方法区的一部分
Compiled from "Main.java"
public class ffish.top.Main {
public ffish.top.Main();
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 hello
2: astore_1
3: new #3 // class java/lang/StringBuilder
6: dup
7: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
10: aload_1
11: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
14: ldc #6 // String world
16: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
22: astore_2
23: ldc #8 // String hello world
25: astore_3
26: ldc #8 // String hello world
28: astore 4
30: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream;
33: aload_2
34: aload 4
36: if_acmpne 43
39: iconst_1
40: goto 44
43: iconst_0
44: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V
47: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream;
50: aload_3
51: aload 4
53: if_acmpne 60
56: iconst_1
57: goto 61
60: iconst_0
61: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V
64: return
}
反编译这段代码。其中ldc指令为加载一个常量到操作数栈。02: astore_1 25: astore_3 28: astore 4
分别对应a c d三个变量,它们都是通过ldc指令加载进来的,所以c和d指向同一块内存
而22: astore_2
也就是变量b,是通过StringBuilder.toString()
的方法生成的
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
通过查看StringBuilder的toString()
的方法,可以看到这里是通过new关键字来生成一个String对象,所以b指向的应该是堆中的字符对象。至于这个堆中的字符串对象和常量池中的字面量的关系,暂时还不太清楚。可能是通过clone的方式,在堆中新生成了一个字符串对象实现的。
代码中的字符串拼接符号 + ,会被编译器重载为StringBuilder
的append()
方法以提高性能.
评论
全部评论 (0)