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

时间:2014-05-22 07:52:07

标签: 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

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

2 个答案:

答案 0 :(得分:5)

前两行几乎正确。从技术上讲,这两行代码不会自己创建任何对象 - 字符串文字实际上是在编译时处理并放入字节码文件中的常量池中,这意味着在您编写的任何代码运行之前,首次加载类时会创建实际的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 

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

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

String s2 = new String("Android");
s2 = s2.intern();
String s3 = new String("java");
s3 = s3.intern();

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

   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        

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

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

答案 1 :(得分:0)

这一行

String  s1="java";

或包含字符串文字的其他行不会创建String对象。它们是在加载包含字符串文字的类期间由JVM创建的,并放在String池中。

对于String.intern(),它不会创建一个新的String,它只是检查一个字符串是否已经在池中,如果它没有将它添加到池中