假设我有两个陈述。
String one = "abc";
String two = new String("abc");
哪一个是堆栈内存并存储在堆中?
这两者有什么区别?
创建了多少个对象以及内存中的引用如何?
最佳做法是什么?
答案 0 :(得分:22)
所有对象都存储在堆上(包括它们的属性)。 1
局部变量(包括参数)总是包含原始值或引用,并存储在堆栈中。 1
所以,对于你的两行:
String one = "abc";
String two = new String("abc");
堆上有两个对象(两个包含"abc"
的String对象)和两个引用,每个对象一个,在堆栈上(提供one
和two
是本地的变量)。
(实际上,准确地说,当涉及到诸如字符串文字之类的实习字符串时,它们存储在所谓的字符串池中。)
创建了多少个对象以及内存中的引用是什么?
有趣的是,你问,因为字符串在Java语言中是特殊的。
但有一件事是保证:每当您使用new
时,您确实会获得新参考。这意味着two
将不引用与one
相同的对象,这意味着在这两行代码之后堆上将有两个对象。
1)从形式上讲,Java语言规范没有规定如何或在何处将值存储在内存中。然而,这(或其变体)通常是如何在实践中完成的。
答案 1 :(得分:7)
第一个被称为 String Literal ,并在程序的编译时创建,第二个是字符串对象并在运行时创建。
在第二种情况下使用 new 关键字,因此它在堆中分配。
在第一种情况下,使用名为实习的机制创建对象。当您尝试创建另一个表示相同字符序列的字符串文字时,则不会创建新的对象编译器,而是引用先前创建并存储在字符串池中的字符串
答案 2 :(得分:4)
只有基本类型的实例(int,long,...)才会保存在堆栈中。引用类型的所有实例(String
,Integer
,Long
,YourTypeHere
,...)都保存在堆中。
UPDATE 正如注释中所指出的,对引用类型实例的引用(即非基本类型 - Object
及其'后代)可以保存在堆栈中。这些是你的局部变量。
这不是“最佳实践”,它是JVM的工作方式,你无法改变它。
答案 3 :(得分:3)
在您的情况下,创建了2个String对象。 通常,所有对象都在堆上创建。但是,由于String 1是字符串文字,因此它将存储在字符串池中(在PermGen中)。您还可以使用intern()方法将字符串添加到字符串池并获取对它的引用。
如果您发布的声明位于方法中,则引用将存储在堆栈中,但不会存储在对象本身中。
至于,我认为最好的做法是: 字符串一=“abc”
这有两个原因:
编辑: 您可能有兴趣查看此链接:Escape Analysis in Java SE 7。它提供了一些影响对象分配的HotSpot相关优化。