如果为内存优化而jvm
创建string pool
,那么为什么每次我们使用new
关键字创建字符串时它都会创建新对象,即使它存在于string pool
?
7 回答
...为什么Java每次使用
new
关键字创建字符串时都会创建新对象,即使它存在于字符串池中?
因为你明确告诉它!new
操作员总是创建一个新对象 。JLS 15.9.4说:
“类实例创建表达式的值是对指定类的新创建对象的引用。每次计算表达式时,都会创建一个新对象。 ”
作为记录,调用...几乎总是一个错误,new String(String)
但在晦涩难懂的情况下它可能很有用。可以想象,您可能想要一个用于equals
返回true
和==
给出的字符串false
。打电话new String(String)
会给你。
对于旧版本的 Java,substring
和trim
可能的其他String
方法将为您提供与原始版本共享后备存储的字符串。在某些情况下,这可能会导致内存泄漏。例如,调用new String(str.trim())
将防止内存泄漏,但代价是创建修剪后的字符串的新副本。构造String(String)
函数保证分配一个新的后备数组并为您提供一个新String
对象。
这种行为在 Java 7 中发生了变化substring
。trim
为了给原始风格的声明和性能设计人员引入了字符串文字。
但是当您使用new
关键字时,您将在堆上而不是在常量池中显式创建对象。
当对象在堆上创建时,没有办法相互共享内存,它们变得完全陌生,不像常量池。
打破堆和常量池之间的障碍String interning
将帮助您。
字符串实习是一种仅存储每个不同字符串值的副本的方法,该副本必须是不可变的
请记住,常量池也是堆的一小部分,在内存共享可用的情况下还有一些额外的好处。
当你写
String str = new String("mystring");
然后它在堆中创建一个字符串对象,就像您创建的其他对象一样。字符串文字“mystring”存储在字符串常量池中。
从Javadocs:
一个字符串池,最初是空的,由 String 类私下维护。
当调用 intern 方法时,如果池中已经包含一个等于该 String 对象的字符串,由 equals(Object) 方法确定,则返回池中的字符串。否则,将此 String 对象添加到池中并返回对该 String 对象的引用。
由此可见,对于任何两个字符串 s 和 t,当且仅当 s.equals(t) 为真时,s.intern() == t.intern() 才为真。
要利用字符串池,您需要使用String#intern
而不是 new。
以下对象将存储在字符串池中:
String s = "hello";
以下对象将存储在堆中(而不是字符串池):
String s = new String ("hello")
强制垃圾回收!如果您只需要一次 String ,那么将它保存在内存中是没有意义的(几乎永远存在。常量池中的 Strings就是这种情况)。不在常量池中的字符串可以像任何其他对象一样被 GC。因此,您应该只将经常使用的字符串保留在常量池中(通过使用文字或实习它们)。
以 String literals ( String s = "string";
) 形式创建的字符串存储在字符串池中,但使用 new ( 调用 String 构造函数创建的字符串String s = new String("string");
不存储在字符串池中。