使用存储在Java内存中的tostring方法创建字符串对象在哪里?

时间:2015-07-24 10:30:43

标签: java string

我正在做一项任务,我得到了以下问题。

使用toString()方法创建的字符串对象在哪里存储在内存中?

String a = Integer.toString(10);
  1. 在常量池中
  2. 在堆上(新操作员对象的区域)

7 个答案:

答案 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()时,它始终会在 内存中创建一个新对象。
  • 如果使用String文字语法创建对象,则可以从字符串池返回现有对象(如果已存在)。否则,它将创建一个新的字符串对象并放入字符串池中以供将来重复使用。
  

使用字符串文字表示法创建字符串时,它会自动调用intern()方法将该对象放入字符串池(如果它不在池已经)。如果是新的,则在对该对象调用intern()方法之前不会自动进行。