2011-10-04 84 views
0

我正在学习SCJP考试,我有一组样本问题,我正在努力。字符串对象和堆

一个问题的答案我不确定,希望这里有人能够帮我把这个问题放在床上。

这里是问题,

考虑:

11. public String makinStrings() { 
12. String s = "Fred"; 
13. s = s + "47"; 
14. s = s.substring(2, 5); 
15. s = s.toUpperCase(); 
16. return s.toString(); 
17. } 

多少字符串调用此方法时对象将被创造出来的?

A. 1 
B. 2 
C. 3 
D. 4 
E. 5 
F. 6 

非常感谢您提供任何帮助。 我非常欣赏它。

+1

可能重复[多少String对象将被创建(http://stackoverflow.com/questions/7370593/how-many-字符串对象将被创建) –

+1

链接的问题甚至包含完全相同的示例。 –

+0

确实,这是一个确切的重复 – Guillaume

回答

7

让我们逐行进行。

一个简单的起点线,没有在这里创建的字符串。

线12

我们要指定字符串"Fred"s。虽然看起来像是在这里创建了一个字符串,但该字符串将存在于常量池中。 JVMS部分2.17.6 Creation of New Class Instances保证在加载周边类时创建最近的字符串文字的对象,在调用方法之前定义该对象的定义为。所以在这一行上不会创建新的字符串对象。

线13

文本字符串"47"被参考,这再次将已经静态创建的(如上述)。但也有调用+运算符,其中创建一个新的字符串以保存连接的结果。这是创建的第一个字符串。

线的substring方法确实创建一个新的String。它与父级共享底层字符数组 - 因此几乎不占用额外的内存 - 但由于字符串是不可变的,每个不同的字符串表示都需要一个不同的对象。 (这可能是一个陷阱 - 我的第一个直觉反应是“啊,由子字符串创建的字符串是特殊的”,但当然它仍然需要创建一个新对象)。

线15

如上 - 大写表示是不同的,所以一个新的字符串必须创建保存结果。

线16

Strings倍率的toString()方法简单地return this - 因此没有额外的字符串被创建。

的字符串中引用的门上

我数这就是这种方法(期间创建两个这些对象共享相同的底层字符数组三个String对象,并有两个预先存在的对象得分文字)。

+0

这个答案重申了这个[链接]的答案(http://stackoverflow.com/questions/7370593/how-many-string-objects-will-be-created/7370800#7370800)所以谢谢你澄清。 – fluffy88

0

我会说3:在线路12,13和15

为什么线14(子)不创建新的对象是因为内部字符串的方式工作的原因的人。由于必须对子字符串进行优化(包括编译器在内的所有东西都依赖于子字符串),所以String类有两个指向字符串开始和结尾的指针。做一个子字符串只会移动这个指针,并不会将该对象“复制”到一个新的。

+0

我同意。尽管'String.toUpperCase()'很棘手,但只有在需要修改任何字符时才会创建新的String对象。 –

+0

从阅读此回复[链接](http://stackoverflow.com/questions/7370593/how-many-string-objects-will-be-created/7370800#7370800)3的确是答案,但在第13行, 谢谢你的回应:) – fluffy88

+0

@JarekPrzygódzki这也是我的想法 - substring不会改变字符,但toUpperCase会(在这种情况下无论如何) – Guillaume

2

实际上,将整个方法变成一个常量是可能的。这是可能的,但编译器不允许这样做。因此,使用常量池中的2创建了3个字符串。

  • Fred47
  • ED4(注意:使用相同背衬的char []作为Fred47虽然)
  • ED4

2和3是相当容易的,因为编译器是不允许优化掉此方法调用但字符串已更改。 Sting.toString()只返回this,所以没有新的字符串。但是,让我们对使用反汇编字节码13号线一看(javap -c在这里你的朋友):

public java.lang.String makinStrings(); 
    Code: 
    0: ldC#16; //String Fred 
    2: astore_1 
    3: new #18; //class java/lang/StringBuilder 
    6: dup 
    7: aload_1 
    8: invokestatic #20; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String; 
    11: invokespecial #26; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V 
    14: ldC#29; //String 47 
    16: invokevirtual #31; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
    19: invokevirtual #35; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 
     // SNIP 
} 

正如你看到的,“弗雷德”和“47”是从常量池(ldc)加载到填充最终将成为String(StringBuilder.toString())的StringBuilder。

这样就可以为每个方法调用创建2个常量字符串和3个新创建的字符串。

+0

现在,这是一个很好的答案,包括反汇编的代码,荣誉。 – Guillaume

0

它会创建串的5个对象

字符串是不可变的类,以便为每一个新字符串,它会创建一个对象。

例如

  1. 公共字符串makinStrings(){
    1. 的String = “佛瑞德”; (此线创建1 --- Fred字符串)
    2. s = s +“47”; (此行创建2-47字符串+ 3- Fred47)
    3. s = s.substring(2,5); (这行创建4-ed4)
    4. s = s.toUpperCase();(这行创建5-ED4)
    5. return s。的toString();

所以根据我来说,这将创造5对象