使用String`s实习方法时会创建多少个对象

sar*_*sar 3 java string

我对String的实习方法没有很好的理解.

String  s1="java";  // should create  one  object in  String Constant  pool

String ss="java"; //  no object is created (java is already in String pool)..it  refers to object in String constant pool


String  s2= new String("Android").intern();  // should create  2 objects one in heap and     second  in String  constant  pool 

String s3=  new String("java").intern()//  i guess only  one  object is created on  heap and  s3 will  point to  object  in String constant  pool (as 'java' already exist).so  the object  in   heap is lost because  there is  no reference
Run Code Online (Sandbox Code Playgroud)

请让我知道我的理解是否正确?

awk*_*ksp 6

你的前两行几乎是正确的.从技术上讲,这两行代码不会自己创建任何对象 - 字符串文字实际上是在编译时处理的,并放在字节码文件的常量池中,这意味着String在类第一次创建实际对象时在您编写的任何代码运行之前加载.因此,如果您要对代码的前两行进行反编译,那么您将得到以下结果:

0: aload_0       
1: invokespecial #1                  // Method java/lang/Object."<init>":()V
4: aload_0       
5: ldc           #2                  // String java
7: putfield      #3                  // Field s1:Ljava/lang/String;
10: aload_0       
11: ldc           #2                  // String java
13: putfield      #4                  // Field ss:Ljava/lang/String;
16: return 
Run Code Online (Sandbox Code Playgroud)

如您所见,任何String一行都不会创建任何对象.字节码只是将String常量池(ldc均值load constant)中的预先存在的值分配给那些变量

接下来的两行有点不同.如果将链式调用拆分为组件部分,可能更容易弄清楚发生了什么:

String s2 = new String("Android");
s2 = s2.intern();
String s3 = new String("java");
s3 = s3.intern();
Run Code Online (Sandbox Code Playgroud)

这会被编译为这个字节码:

   0: new           #2                  // class java/lang/String
   3: dup           
   4: ldc           #3                  // String Android
   6: invokespecial #4                  // Method java/lang/String."<init>":(Ljava/lang/String;)V
   9: astore_1      
  10: aload_1       
  11: invokevirtual #5                  // Method java/lang/String.intern:()Ljava/lang/String;
  14: astore_1      
  15: new           #2                  // class java/lang/String
  18: dup           
  19: ldc           #6                  // String java
  21: invokespecial #4                  // Method java/lang/String."<init>":(Ljava/lang/String;)V
  24: astore_2      
  25: aload_2       
  26: invokevirtual #5                  // Method java/lang/String.intern:()Ljava/lang/String;
  29: astore_2      
  30: return        
Run Code Online (Sandbox Code Playgroud)

因此,您可以看到该new关键字触发了新String对象的构造.然后"Android"从常量池加载字符串并用于创建字符串.然后将其存储到变量中.紧接着,该变量被解除引用,intern()被调用,并且结果存储回变量中.这段代码与您的代码之间的唯一区别在于String构造和实习之间的额外存储/负载.

因此,对于每个s2s3,只String创建一个对象 - 因此,您只看到两个方法<init>总计.所有intern()操作都是检查字符串池中是否已存在该字符串,如果存在,则返回该引用.