【问题标题】:Number of objects created when using String intern method in Java在 Java 中使用 String intern 方法时创建的对象数
【发布时间】:2014-09-20 12:33:39
【问题描述】:

我了解String的intern方法。

String s1 = "Hello";             
String s4 = new String("Hello").intern();  

(s1 == s4) 的输出将是 true,如果我们不使用 intern,它将是 false

我的问题是在执行上面两个语句时,会创建多少个对象?一个或两个? new 运算符会再创建一个对象吗?

我知道String s4 = new String("Hello") 会创建两个对象,但对使用intern 感到困惑。

【问题讨论】:

  • 我收回来,第二行末尾的.intern() 使它与thisthisthis 不同。
  • 这是一个有技巧的问题,因为数字可能是 2、3 或 4。
  • (但是这个相同的问题以前也有人问过。这显然是一个标准的面试问题或类似的问题。而且是一个愚蠢的问题(因为似乎很多面试问题都是如此)。)

标签: java string object


【解决方案1】:

会是两个

一个

String s1 = "Hello"; 

另一个

String s4 = new String("Hello")

【讨论】:

  • 那么,上面的intern有什么用呢?
  • 与实习生一起,它将查看字符串文字“Hello”的永久空间。所以在这里你没有与实习生取得任何成就
  • @Anand - Intern 导致返回原始的“Hello”实例。
  • @Hot Licks- 那么有什么好处呢?
  • @Anand 你想引用实习生的情况是引用相同的字符串对象,例如基于哈希的数据结构键。
【解决方案2】:

当你需要优化你的代码时你应该使用实习生,因为通过引用比较字符串更快。

至于你的说法,只会创建两个对象。

请注意,过多使用实习生可能会导致内存异常,因为它们存储在通常很小的 PermGen 中,因此请确保正确配置 JVM。

【讨论】:

  • intern 仅对相同值的重复比较有用,因为intern 操作本身非常昂贵。
  • 在 15 年的 Java 编程生涯中,我从未见过需要使用 intern() 进行优化的案例。但是,我看到了一些不必要地使用它和/或实际上使性能变差的情况。
【解决方案3】:

...将创建多少个对象?一两个?

两个。但其中只有一个被保留。另一个立即有资格进行垃圾收集。

new 运算符会再创建一个对象吗?

是的。简要地。但是你调用它的.intern 方法并保存结果。它的.intern 方法将返回与s1 指向的相同的内部字符串,因此通过new 创建的对象(再次)立即符合GC 条件。

如果我们查看字节码,我们可以看到这一点:

公共静态无效主(java.lang.String[]); 代码: 0: ldc #2 // 字符串你好 2:astore_1 3: new #3 // 类 java/lang/String 6:重复 7: ldc #2 // 字符串你好 9: invokespecial #4 // 方法 java/lang/String."":(Ljava/lang/String;)V 12: invokevirtual #5 // 方法 java/lang/String.intern:()Ljava/lang/String; 15:astore_2 16: getstatic #6 // 字段 java/lang/System.out:Ljava/io/PrintStream; 19:加载_2 20: invokevirtual #7 // 方法 java/io/PrintStream.println:(Ljava/lang/String;)V 23: getstatic #6 // 字段 java/lang/System.out:Ljava/io/PrintStream; 26:加载_1 27:加载_2 28: if_acmpne 35 31:图标st_1 32:转到 36 35:图标st_0 36: invokevirtual #8 // 方法 java/io/PrintStream.println:(Z)V 39:返回

3-9 从"Hello" 创建一个新的String 对象,将它的引用留在堆栈上,然后我们立即调用intern(它从堆栈中弹出对新字符串的引用),并存储interns4 中的返回值。所以临时创建的对象不再被引用。

【讨论】:

  • 谢谢..但是我们通过使用实习生可以实现什么?
  • @Anand:当someString 是一个更大字符串的子字符串并且你要坚持很长时间时,习惯使用new String(someString).intern()。在 Java 的大部分生命周期中,如果您使用 someString = someBigString.substring(10, 20)someStringsomeBigString 引用相同的字符数组(所有字符都为 someBigString)。所以如果你释放了someBigString,那就是内存泄漏——someString 引用了它实际上没有使用的字符。成语解决了这个问题。从 1.7.0_06 开始,字符串不再共享 char 数组。
  • @HotLicks:没有关注你。通过substring 创建的字符串共享底层char 数组,使用offsetcount 很好地进入1.7(具体来说,直到我上面提到的1.7.0_06)。只需查看 1.7.0_05 中 String.java 的来源,特别是第 1,961 和 645 行。我一定误解了您的评论。
  • @HotLicks:那么您正在查看 1.7.0_05 之后的内容。在 1.7.0_05(以及以前,在我看过的各种版本中)中,substring 在正常情况下返回这个 new String(offset + beginIndex, endIndex - beginIndex, value) 这是一个私有构造函数,它只设置 valueoffsetcount ,导致 char 数组的重用。
  • @HotLicks:1.1.8_16、1.2.2_017 和 1.3.1_29 中的代码完全相同(看起来几乎没有改动)。我认为您一定是在使用非 Sun 资源,或者(应有的尊重!)您只是记错了(1.2 很久以前)。由于它显然直到 1.7.0_06 才被废弃,我们可能应该清理这些 cmets。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-15
  • 1970-01-01
  • 2011-03-20
  • 1970-01-01
  • 1970-01-01
  • 2021-01-16
相关资源
最近更新 更多