【问题标题】:How many objects are created when we use String`s intern method [duplicate]当我们使用String的intern方法时创建了多少个对象[重复]
【发布时间】:2014-05-22 07:52:06
【问题描述】:

我对String的intern方法不太了解。

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

请告诉我我的理解是否正确?

【问题讨论】:

标签: java string


【解决方案1】:

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

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 对象——因此,您只会看到两个带有&lt;init&gt; 的方法。 intern() 所做的只是检查该字符串是否已存在于字符串池中,如果存在,则返回该引用。

【讨论】:

  • 从技术上讲,对象是在链接/类加载时创建的,而不是编译时。
  • @chrylis 当然,我想你可以这样说......我更多地认为创建对象的所有信息都在编译时被放入字节码中的常量池中,但它说实际对象是在运行时的某个时间创建的更有意义......我会更正我的答案。
【解决方案2】:

这一行

String  s1="java";

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

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

【讨论】:

    猜你喜欢
    • 2014-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-28
    • 2012-02-26
    • 2014-07-12
    • 2014-08-01
    相关资源
    最近更新 更多