2015-02-24 32 views
0

另一个考试的问题,这让我感到困惑:String对象计数SCJP

public String makinStrings() { 
String s = “Fred”; 
s = s + “47”; 
s = s.substring(2, 5); 
s = s.toUpperCase(); 
return s.toString(); 
} 

的问题是: “?有多少String对象时,调用此方法将创建”

正确的答案应该是3,但是我统计了:
弗雷德
Fred47
ED4
ED4

是3真的是正确的答案?如果是这样 - 为什么?

回答

1

字符串常量在类被实例化的时刻被实例化。因此,字符串“Fred”和“47”在方法调用之前实例化,而不是在方法调用期间实例化。

这篇文章解释它:The String Constant Pool

但我会完善多一点:Java虚拟机规范规定的常量“弗雷德”和“47”被放置在字符串常量池项。 (java SE specs, loading and linking)。

发生这种情况当班级被加载

另一个需要注意的问题是:问题是有多少对象实例化了

所以,

的String =“佛瑞德”:不实例化新的字符串对象,仅使用从内化“佛瑞德”恒定的参考。

s = s +“47”:'+'运算符意味着级联操作;该连接的结果是一个新的String对象。所以,1个字符串实例化。在“47”中装入类...

S = s.substring(2,5):方法定义指定一个新的字符串对象必须返回(String.substring javadoc),所以,2个字符串实例化。

即使实现(这种情况,例如the openJDK java.lang.String implementation)可以使用某种类型的构造,以仅参考字符阵列具有字符串内部值,则结果的一部分是一个新的字符串,即使一种“懒惰”的。

s = s.toUpperCase():在这里相同,toUpperCase方法必须返回一个新的String。所以,3个字符串被实例化了。

最后,s.toString()以String形式返回对象的表示形式。由于字符串已经是一个字符串,s.toString()只返回完全相同的字符串对象...

+0

从Java语言规范[常量池自Java 7以来已移至Java堆](http://www.oracle.com/technetwork/java/javase/jdk7-relnotes-418459.html#jdk7changes),以及之前该池在热点JVM上位于'permgen space'中。 – 2015-02-24 12:26:49

+1

这并不排除字符串常量在方法调用过程中没有实例化的事实,但是当类被实例化时,是不是? – 2015-02-25 23:59:19

+0

Nopes它不排除,但评论是在您的缓存内存概念提到的答案的前一个版本...... – 2015-02-26 09:27:46

0

3个对象:
弗雷德
Fred47
ED4

s = s + “47”; 

47不会在字符串池中创建

s = s.substring(2, 5); 

不应该创建一个单独的字符串,但将遵循flyweight模式和内部指向相同的字符串。

+0

为什么47不会在字符串池中创建,如果没有,那么它将在哪里创建?和's.substring(2,5)'一定会在堆内存中创建新的字符串'对象' – 2015-02-26 09:28:04