我正在做一项任务,我得到了以下问题。
使用toString()
方法创建的字符串对象在哪里存储在内存中?
String a = Integer.toString(10);
答案 0 :(得分:22)
它们全都进入堆内存。只有字符串文字和实习字符串才会进入字符串常量池。
唯一的例外是像String
这样的类:
public String toString() {
return this;
}
它只返回当前字符串(如果它在堆上,它从堆返回/如果它在字符串常量池上,它从字符串常量池返回)
注意:如果未覆盖toString()
以显式返回 String Literal ,则表示字符串表示(ClassName @ hexValueOfHashCode)始终在堆上创建。
答案 1 :(得分:11)
这取决于您正在调用的toString()
方法的实现。
toString()
方法创建String
对象,因此取决于它是如何做到的(以及它是否实际插入字符串),返回的String
将在字符串池中或不。
请注意toString()
只是一种方法,就像任何其他方法一样。没有魔法以任何特殊方式处理toString()
方法的返回值。 (toString()
返回的字符串例如不会自动实现。)它的工作方式与返回String
的任何其他方法完全相同。
答案 2 :(得分:8)
这是一个奇怪的(我会说很差)面试问题,你被问到,因为这个问题的答案取决于JDK的实施。这种实现可能会发生变化,而不是普通人所期望的,因为要确定,您需要询问实施者或阅读他们的源代码。此外,从Java 7开始,字符串池(我假设的是“常量池”)就在堆上。所以即使它在字符串池中,它仍然在堆上。
目前(OpenJDK 8u40-b25),String
将是在堆内存中创建的新对象:
public static String toString(int i) {
if (i == Integer.MIN_VALUE)
return "-2147483648";
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
char[] buf = new char[size];
getChars(i, size, buf);
return new String(buf, true);
}
由于您传递的是10
,而不是Integer.MIN_VALUE
,因此会创建一个新的String
对象。此字符串的内容是使用char
创建的new
数组,因此存在于堆上。 <{1}}未被调用,因此不会将其放入字符串池中。
如果intern()
与==
测试它们是同一个对象,而不是相同的值,则可以测试这是您获得的行为。以下将评估为String
,因为静态False
方法在每次调用时都在堆上创建了一个新的Integer.toString()
对象:
String
如果它们被插入到字符串池中,它们将是同一个对象(因为这是实习点 - 每个字符串只有一个对象)。以下评估结果为Integer.toString(10) == Integer.toString(10)
:
True
请注意,这是专门针对静态Integer.toString(10).intern() == Integer.toString(10).intern()
方法的答案,而不是针对所有Integer.toString()
方法。例如,toString()
返回字符串池中的字符串。
答案 3 :(得分:3)
你提出的问题是有缺陷的。
首先,两个选项:(1)返回常量池中的字符串,以及(2)返回新创建的字符串,不是互斥的,因为方法可以创建新字符串,但是{ {3}}它将它带入常量池。
其次,没有特定要求toString()
方法如何提供一般的字符串。这完全取决于特定toString()
方法的特定实现。你无法概括并说他们都做了某件事。
某些方法可能会在每次通话时返回new String(...)
(适合比较StringBuilder
)。
有些方法总是可以从一小组固定的可能性中返回一个字符串实例,这些固定的可能性也可能也在常量池中(适用于类{{1})或者对于枚举常量)。
有些方法可能会混合使用。 Boolean
可能会为小公共值使用一组预定义常量,但会返回新的堆字符串以获取更多模糊值。或者它可以按需生成和缓存字符串,以便Integer.toString(int)
可以在第一次返回新的堆字符串,但在后续调用时返回相同的堆字符串;在这种情况下,如果调用者Integer.toString(10)
某处Integer.toString
的返回值,那么.intern()
类的按需缓存实例也可以进入常量池。
行为也可能因JVM风格或JVM版本或传递给它的运行时选项而异。
关于Integer
目前在OpenJDK 8中做什么的具体问题,intern()
:
Integer.toString(int)
事实证明,它为public static String toString(int i) {
if (i == Integer.MIN_VALUE)
return "-2147483648";
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
char[] buf = new char[size];
getChars(i, size, buf);
return new String(buf, true);
}
返回一个字符串文字(将在常量池中),但是为每个其他值返回一个新的堆字符串。 (它可能看起来很奇怪,但许多编程语言中的数字到字符串函数通常以这种方式对min值进行例外处理,因为使用check the source表示整数时,最大值比最小值的绝对值(例如,-2,147,483,648到+2,147,483,647的范围),这意味着最小值是唯一的负值,您不能将其转换为正值,然后使用与正值相同的共享循环代码进行处理。)< / p>
问题的第三个问题是答案几乎不重要。只有当你发现Integer.MIN_VALUE
方法的实现不起作用或性能不令人满意时,你才能调查原因,但除此之外,只要它有效,并且有效地工作,为什么有人会关心它如何缓存字符串或它是否缓存它们? Java新手对于愚蠢的字符串常量池的细节过于担心,这是一个令人遗憾的副作用,因为Java决定不对toString()
调用==
对象,这使得恒定池的行为更加明显。
当你需要一个明确在常量池中的字符串时,你可以自己实习,或者在源代码中将其写成字符串文字。否则,您无法保证它是否在恒定池中,也不需要这样的保证。
根据.equals()
的实施情况,他们可能正在寻找答案 2 (“在堆上”),但对于一个存在严重缺陷的问题,这是一个有缺陷的答案。
答案 4 :(得分:1)
我认为它应该取决于实施。但是对于来自java.lang.Object
和许多其他对象的默认toString&#39; toString
实现仅返回字符串文字。所以我可以告诉你它们在字符串常量池中,因为默认情况下它们是interned
,并且所有实体字符串都将存储在字符串常量池中。
示例1
public String toString() {
return "my test string"; // will be in string constant pool
}
示例2
public String toString() {
String s1 = new String("my test string");
return s1; // s1 will be in heap
}
当然,我不必告诉你s1.intern()
将示例字符串放在字符串常量池中(如果尚未提供)
答案 5 :(得分:1)
在Integer包装器类中,一旦将给定的int解析为char,它将返回一个新的String对象。
return new String(buf, true);
这将在堆内存中创建1个字符串对象。
参考变量&#34; a&#34;将指向堆中的对象(普通内存)。
但请记住,
String str = new String("abc");
将创建2个对象,一个在堆中,另一个在String池中。
编译时间常量String类型的表达式始终是实例化的。
答案 6 :(得分:0)
依赖于实现。但是,默认情况下,字符串将转到字符串池。
案例1:
public String toString() {
return "Constant Pool"; // String constant pool
}
案例2:
public String toString() {
String string2 = new String("Heap String");
return string2; // in heap
}
两个表达式都为您提供String
个对象,但它们之间存在细微差别。
String
运算符创建new()
时,它始终会在堆 内存中创建一个新对象。 使用字符串文字表示法创建字符串时,它会自动调用
intern()
方法将该对象放入字符串池(如果它不在池已经)。如果是新的,则在对该对象调用intern()
方法之前不会自动进行。