我对这两件事感到困惑。我需要帮助。请清楚我的疑问,String Constant Pool和String pool是否都是相同的概念。我在采访中遇到了这个问题。我已经阅读了很多网站和博客但是,我的疑问还没有清除。请清除我的疑虑。
先谢谢。
答案 0 :(得分:4)
两者都是一回事。 String Constant Pool包含常量字符串对象。 Constant
可以定义为String对象在编译时保存该值。有关详情,请参阅JLS。
String s="abc";
String s1="def";
String s2=s+"def";
String s3="abc"+"def";
System.out.println(s2==s3); // print false
但如果你将s
定为最终
final String s="abc";
String s1="def";
String s2=s+"def";
String s3="abc"+"def";
System.out.println(s2==s3); // print true
在上面的情况中,s3
是编译时常量,因为s是最终的。
答案 1 :(得分:3)
字符串池(=“字符串常量池”):
这是String的类级/静态实习存储的非正式昵称。注意:javadoc提到“字符串池”http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#intern%28%29。
它是一个包含在应用程序执行期间实现的每个唯一String值的集合。对于所有编译时字符串常量(文字和固定表达式)以及调用String.intern()
的所有运行时字符串值,都会自动进行实习。 JLS强制要求String类型的编译时常量表达式始终“实例化”,以便使用String.intern方法共享唯一实例。 http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.28
JVM规范没有强制要求对象的任何特定内部结构。 http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html#jvms-2.7
Java语言规范要求String对象具有常量(不变)值。 http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.3.3
这意味着String变量只能通过引用具有新值的新String对象来更改值 - 当然,这是由编译器和内部管理的。 JVM。这也意味着池中的所有项都是字符串常量。
常量池(不专注于字符串,但确实包含字符串):
答案 2 :(得分:2)
我考虑过它并且我不确定但是字符串池可能引用字符串文字池,像String apple = "apple";
这样的东西,因为String常量池可能引用常量字符串对象,如使用关键字的那些最后,虽然接受一个棘手的语义问题,如果我在面试中得到它会惹恼我
答案 3 :(得分:0)
字符串池(字符串常量/内存/文字池)与常量池
当编译器遇到任何字符串文字时,编译器会将其放入String Constant Pool中。所有方法或类变量都引用该字符串常量池;
class MemoryModel { final String s = "abc"; String s5 = "abc";}
:
String s1 = "abc";
MemoryModel mm = new MemoryModel();
System.out.println("abc".hashCode()); //12345
System.out.println(mm.s.hashCode()); //12345
System.out.println(mm.s5.hashCode()); //12345
System.out.println(s1.hashCode()); //12345
字符串“abc”将转到字符串池,而s,s5将进入类MemoryModel的常量池(或运行时常量池)。 's1'是方法局部变量,因此它将保存在JVM框架中。
示例2
public method(){
final String s="abc";
String s1="def";
final String s2=s+s1;
String s3=s+"def";
String s4="abc"+"def";
}
对于上述方法,类常量池中不会保存任何内容。 “abc”,“def”和“abcdef”将保存在String池中。
"abcdef".hashCode() == ("abc" + "def").hashCode() //true
上述方法的字节码;
0: ldc #19 // String abc
2: astore_1
3: ldc #21 // String def
5: astore_2
6: new #23 // class java/lang/StringBuilder
9: dup
10: ldc #19 // String abc
12: invokespecial #25 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
15: astore_3
16: aload_3
17: aload_2
18: invokevirtual #28 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
21: invokevirtual #32 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
24: astore 4
26: ldc #36 // String abcdef
28: astore 5
30: ldc #36 // String abcdef
32: astore 6
34: return
以上字节码表示没有任何内容放入CP(常量池)。对于上面的代码s3 == s4和s3 ==“abcdef”,因为所有最终常量都在编译时被替换为它们的值。所以上面的代码将被转换为这个;
final String s="abc";
String s1="def";
final String s2=new StringBuilder("abc").append(s1).toString();
String s3="abc"+"def";
String s4="abc"+"def";
但如果's'不是最终的那么
String s="abc";
String s1="def";
final String s2=new StringBuilder(s).append(s1).toString();
String s3=new StringBuilder(s).append("def").toString();
String s4="abc"+"def";
在上面的代码中,s2和s3将指向具有char []的String的新实例。所以s3和s4不一样。
示例3
public class MemoryModel {
final String s="abc";
String s1="def";
final String s2=s+s1;
String s3=s+"def";
String s4="abc"+"def";
String s5=s2;
}
字节码与上面的字节码非常相似。但是,您会看到更多putfield
和getfield
的条目,这些条目告诉我们将常量放入CP中。
让我们比较上面代码的字节代码;
使用Final的'
21: ldc #8 // String abc
23: invokespecial #27 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
26: aload_0
27: getfield #23 // Field s1:Ljava/lang/String;
30: invokevirtual #30 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
33: invokevirtual #34 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
36: putfield #38 // Field s2:Ljava/lang/String;
没有决赛'
21: aload_0
22: getfield #18 // Field s:Ljava/lang/String;
25: invokestatic #26 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
28: invokespecial #32 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
31: aload_0
32: getfield #22 // Field s1:Ljava/lang/String;
35: invokevirtual #35 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
38: invokevirtual #39 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
41: putfield #43 // Field s2:Ljava/lang/String;
和
使用Final的'
39: aload_0
40: ldc #40 // String abcdef
42: putfield #42 // Field s3:Ljava/lang/String;
没有决赛'
44: aload_0
45: new #24 // class java/lang/StringBuilder
48: dup
49: aload_0
50: getfield #18 // Field s:Ljava/lang/String;
53: invokestatic #26 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
56: invokespecial #32 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
59: ldc #20 // String def
61: invokevirtual #35 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
64: invokevirtual #39 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
67: putfield #45 // Field s3:Ljava/lang/String;
此比较还证明在比较时替换最终变量的值。并且常量字段保存到CP中。因此,如果's'不是最终的那么's的值是使用getfield从CP中获取的。