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指向另一块内存。
请问其中原理是什么?
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号
Java的运行时数据区中,有一个方法区(Method Area)和堆(Heap)。
对于那些在编译时就能确定的字面量都会存放在运行时常量池中,而常量池是方法区的一部分
反编译这段代码。其中ldc指令为加载一个常量到操作数栈。
02: astore_1 25: astore_3 28: astore 4分别对应a c d三个变量,它们都是通过ldc指令加载进来的,所以c和d指向同一块内存而
22: astore_2也就是变量b,是通过StringBuilder.toString()的方法生成的通过查看
StringBuilder的toString()的方法,可以看到这里是通过new关键字来生成一个String对象,所以b指向的应该是堆中的字符对象。至于这个堆中的字符串对象和常量池中的字面量的关系,暂时还不太清楚。可能是通过clone的方式,在堆中新生成了一个字符串对象实现的。Tip: 代码中的字符串拼接符号 + ,会被编译器重载为
StringBuilder的append()方法以提高性能因为b包含了一个a的引用,a指向另一内存,b也必须被分配到另一内存。
你要明白字符串常量和变量是不一样的,字符串常量池里面有对象的时候,再次分配的时候,只是改变了引用的指针,不开辟新的空间,而变量在创建的时候,作为一个新的对象开辟一个空间,指向不同的引用。这也就是c、d指向同一块内存地址,而b指向另一块。
谢谢大神们的回答,豁然开朗,简单总结下:
对于那些在编译时就能确定的字面量都会存放在运行时常量池中,比如:
而如下代码
其中a是变量,在编译时不能确定值,所以不会被放在运行时常量池中,而是在heap中重新new了一块儿内存。