11

如果为内存优化而jvm创建string pool,那么为什么每次我们使用new关键字创建字符串时它都会创建新对象,即使它存在于string pool

4

7 回答 7

30

...为什么Java每次使用new关键字创建字符串时都会创建新对象,即使它存在于字符串池中?

因为你明确告诉它!new操作员总是创建一个新对象 。JLS 15.9.4说:

“类实例创建表达式的值是对指定类的新创建对象的引用。每次计算表达式时,都会创建一个新对象。


作为记录,调用...几乎总是一个错误,new String(String)但在晦涩难懂的情况下它可能很有用。可以想象,您可能想要一个用于equals返回true==给出的字符串false。打电话new String(String)会给你。


对于旧版本的 Java,substringtrim可能的其他String方法将为您提供与原始版本共享后备存储的字符串。在某些情况下,这可能会导致内存泄漏。例如,调用new String(str.trim())将防止内存泄漏,但代价是创建修剪后的字符串的新副本。构造String(String)函数保证分配一个新的后备数组并为您提供一个新String对象。

这种行为在 Java 7 中发生了变化substringtrim

于 2015-09-23T07:28:05.880 回答
5

为了给原始风格的声明和性能设计人员引入了字符串文字。

但是当您使用new关键字时,您将在堆上而不是在常量池中显式创建对象。

当对象在堆上创建时,没有办法相互共享内存,它们变得完全陌生,不像常量池。

打破堆和常量池之间的障碍String interning将帮助您。

字符串实习是一种仅存储每个不同字符串值的副本的方法,该副本必须是不可变的

请记住,常量池也是堆的一小部分,在内存共享可用的情况下还有一些额外的好处。

于 2015-09-23T07:13:01.047 回答
3

当你写

String str = new String("mystring"); 

然后它在堆中创建一个字符串对象,就像您创建的其他对象一样。字符串文字“mystring”存储在字符串常量池中。

Javadocs

一个字符串池,最初是空的,由 String 类私下维护。

当调用 intern 方法时,如果池中已经包含一个等于该 String 对象的字符串,由 equals(Object) 方法确定,则返回池中的字符串。否则,将此 String 对象添加到池中并返回对该 String 对象的引用。

由此可见,对于任何两个字符串 s 和 t,当且仅当 s.equals(t) 为真时,s.intern() == t.intern() 才为真。

于 2015-09-23T07:16:05.113 回答
1

要利用字符串池,您需要使用String#intern而不是 new。

于 2015-09-23T07:12:42.307 回答
0

以下对象将存储在字符串池中:

String s = "hello";

以下对象将存储在堆中(而不是字符串池):

String s  = new String ("hello")
于 2015-09-23T07:15:06.480 回答
0

强制垃圾回收!如果您只需要一次 String ,那么将它保存在内存中是没有意义的(几乎永远存在。常量池中的 Strings就是这种情况)。不在常量池中的字符串可以像任何其他对象一样被 GC。因此,您应该只将经常使用的字符串保留在常量池中(通过使用文字或实习它们)。

于 2015-09-23T07:16:46.050 回答
0

以 String literals ( String s = "string";) 形式创建的字符串存储在字符串池中,但使用 new ( 调用 String 构造函数创建的字符串String s = new String("string");不存储在字符串池中。

于 2015-09-23T07:26:04.137 回答