我知道String literal和新String对象之间的区别,也知道它是如何在内部工作的。但我的问题是稍微提前一点。当我们使用new关键字创建String对象时
String str = new String("test");
在这种情况下,我们传递一个String类型的参数。 我的问题是这个字符串生成的地方 - 堆或字符串常量池还是其他地方?
据我所知,这个参数是一个字符串文字所以它应该在String常量池中。如果它是那么使用intern
方法 - 只是链接变量str
到恒定池?因为"test"
已经可用。
如果我误解了这个概念,请澄清一下。
答案 0 :(得分:9)
语句String str = new String("test");
创建一个字符串对象,它像任何其他对象一样存储在堆上。作为参数传递的字符串文字"test"
存储在字符串常量池中。
String#intern()
检查字符串池中是否已有字符串常量。如果有一个已经返回它,否则它会创建一个新的并将其存储在池中。请参阅Javadocs:
返回字符串对象的规范表示。
字符串池(最初为空)由类
String
私有维护。当调用intern方法时,如果池已经包含与
equals(Object)
方法确定的此String对象相等的字符串,则返回池中的字符串。否则,将此String
对象添加到池中,并返回对此String
对象的引用。对于任何两个字符串
s
和t
,s.intern() == t.intern()
当且仅当s.equals(t)
为真时才为真。
从JDK7开始,实习字符串存储在堆上。这来自release notes of JDK7:
在JDK 7中,实例化的字符串不再分配在Java堆的永久生成中,而是分配在Java堆的主要部分(称为年轻和旧的代),以及创建的其他对象通过申请。此更改将导致更多数据驻留在主Java堆中,并且永久生成中的数据更少,因此可能需要调整堆大小。由于此更改,大多数应用程序只会看到堆使用中的相对较小的差异,但是加载许多类或大量使用
String.intern()
方法的较大应用程序将看到更显着的差异。
答案 1 :(得分:7)
使用intern()
:
public static void main(String[] args) throws IOException {
String s = new String(new char[] { 'a', 'b', 'c' }); // "abc" will not be added to String constants pool.
System.out.println(System.identityHashCode(s));
s = s.intern();// add s to String constants pool
System.out.println(System.identityHashCode(s));
String str1 = new String("hello");
String str2 = "hello";
String str3 = str1.intern();
System.out.println(System.identityHashCode(str1));
System.out.println(System.identityHashCode(str2));
System.out.println(System.identityHashCode(str3));
}
O / P:
1414159026
1569228633 --> OOPs String moved to String constants pool
778966024
1021653256
1021653256 --> "hello" already added to string pool. So intern does not add it again.
答案 2 :(得分:3)
当您使用String str = new String("test");
时,它将创建两个对象和一个引用变量。在这种情况下,JVM将在普通(非池)堆内存中创建一个新的字符串对象,文字"test"
将放在字符串常量池中。变量str
将引用堆中的对象(非池)。