字符串常量池与字符串池

我对这两件事很困惑。 我需要帮助。 请清楚我的疑问,String Constant Pool和String pool是否都是相同的概念。 我在面试中遇到了这个问题。 我已经阅读了很多网站和博客,但我的疑问还没有清除。请清除我的疑虑。

提前致谢。

两者都是一回事。 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 

但是,如果你最后决定

  final String s="abc"; String s1="def"; String s2=s+"def"; String s3="abc"+"def"; System.out.println(s2==s3); // print true 

在上面的情况中, s3是编译时常数,因为s是最终的。

字符串池(=“字符串常量池”):

常量池(不专注于字符串,但确实包括字符串):

我考虑过它并且我不确定但是字符串池可能引用了字符串文字池,比如String apple = "apple"; 其中String常量池可以引用常量字符串对象,就像那些使用关键字final的那样,虽然接收一个棘手的语义问题,如果我在面试中得到它会让我烦恼

字符串池(字符串常量/内存/文字池)与常量池

当编译器满足任何字符串文字时,编译器会将其放入字符串常量池中。 所有方法或类变量都引用该字符串常量池;

 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框架中。

在此处输入图像描述

  • 字符串文字始终引用类String的相同实例。
  • 任何包的任何类中的文字字符串表示对同一String对象的引用。
  • 由常量表达式计算的字符串在编译时计算,然后将其视为文字。

例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."":(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; } 

字节码与上面的字节码非常相似。 但是你会看到更多的putfieldgetfield条目告诉我们CP不变。

让我们比较上面代码的字节代码;

决赛”

  21: ldc #8 // String abc 23: invokespecial #27 // Method java/lang/StringBuilder."":(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."":(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; 

决赛”

  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."":(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; 

该比较还certificate在比较时替换最终变量的值。 并且常量字段保存到CP中。 因此,如果’s’不是最终的那么’s的值是使用getfield从CP中获取的。