Java 字符串对象和堆
我正在为SCJP考试学习,我有一套我正在研究的问题样本 一个问题的答案我不确定,希望这里有人能帮我把这个问题解决 问题是 鉴于:Java 字符串对象和堆,java,string,object,heap,Java,String,Object,Heap,我正在为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. } 调用此方法时将创建多
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
提前感谢您提供的任何帮助。
我非常感激。我想说3:第12行、第13行和第15行的那些
第14行(子字符串)没有创建新对象的原因是字符串的内部工作方式。由于对子字符串进行了必要的优化(包括编译器在内的所有内容都依赖于子字符串),String类有两个指向字符串开头和结尾的指针。执行子字符串只会移动此指针,而不会将对象“复制”到新指针中。让我们逐行查看它 第11行 一个简单的开始,这里没有创建字符串 第12行 我们正在将字符串
“Fred”
分配给s
。虽然看起来这里创建了一个字符串,但该字符串将存在于常量池中。该部分保证字符串文本的对象最迟将在加载周围类时创建,根据定义,这是在调用该方法之前。因此,不会在此行上创建新的字符串对象
第13行
引用了文本字符串“47”
,该字符串将再次静态创建(如上所述)。然而,还有+
操作符的调用,它将创建一个新字符串以保存连接的结果。这是创建的第一个字符串
第14行
substring
方法确实创建了一个新字符串。它与其父级共享底层字符数组,因此几乎不占用任何额外内存,但由于字符串是不可变的,每个不同的字符串表示都需要不同的string
对象。(这可能是一个问题-我的第一个本能反应是“啊,子字符串创建的字符串是特殊的”,但当然它仍然需要创建一个新对象)
第15行
如上所述-大写表示不同,因此必须创建一个新字符串来保存结果
第16行
Strings
重写toString()
方法以简单地返回该字符串
——因此不会创建额外的字符串
门上的分数
根据我的统计,这是在这个方法中创建的三个字符串对象(其中两个对象共享相同的底层字符数组,并且字符串文本引用了两个预先存在的对象)。实际上,可以将整个方法变成一个常量。这是可能的,但编译器不允许这样做。因此,使用常量池中的2创建了3个字符串
- 弗雷德47
- ed4(注意:使用与Fred47相同的支持字符[])
- ED4
这个
,因此也没有新字符串。但是让我们看看第13行中使用的反汇编字节码(javap-c
是您的朋友):
public java.lang.String makinStrings();
代码:
0:ldc#16//串弗雷德
2:astore_1
3:新#18//类java/lang/StringBuilder
6:dup
7:aload_1
8:invokestatic#20//方法java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
11:特别是#26//方法java/lang/StringBuilder。“”:(Ljava/lang/String;)V
14:最不发达国家29//串47
16:invokevirtual#31//方法java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19:invokevirtual#35//方法java/lang/StringBuilder.toString:()Ljava/lang/String;
//剪断
}
如您所见,“Fred”和“47”从常量池(ldc
)加载,以填充最终将成为字符串的StringBuilder(StringBuilder.toString())
这样,每个方法调用就可以生成2个常量字符串加上3个新创建的字符串。它将创建字符串的5个对象 字符串是不可变的类,所以对于每个新字符串,它都将创建一个对象 范例
因此,根据我的说法,它将创建5个对象链接问题的可能重复项,甚至包含完全相同的示例。没错,我同意这是完全重复的。尽管
String.toUpperCase()
很棘手-新的字符串
对象只有在有任何字符需要更改的情况下才会创建。从阅读此响应中,3确实是答案,但在第13、14和15行。感谢您的响应:)@JarekPrzygódzki我也这么认为-子字符串不会更改字符,但toUpperCase会更改字符(无论如何,在本例中)@Guillaume我不同意你的推理。我只同意最终结果是正确的..子字符串(..)确实创建了字符串的新实例(特例s.substring(0,s.length())
是唯一返回this
)的实例。但它使用相同的字符[]。包私有构造函数String(int offset,int count,char[]value)
用于此特殊目的。注意:所有使用char[]的公共可见构造函数都将制作一个副本。此答案重申了此答案,因此感谢您的澄清。这是一个很好的答案,包括反汇编
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
}