如果 jvm
为了内存优化创建了 字符串池
,那么为什么每次我们使用 new
关键字创建字符串时,即使它已经存在于 字符串池
中,它也会创建一个新的对象呢?
如果 jvm
为了内存优化创建了 字符串池
,那么为什么每次我们使用 new
关键字创建字符串时,即使它已经存在于 字符串池
中,它也会创建一个新的对象呢?
new
关键字创建字符串时,即使它已经存在于字符串池中,Java也会每次都创建一个新对象?new
操作符总是会创建一个新的对象。根据JLS 15.9.4的规定:new String(String)
几乎总是错误的... 但在某些特殊情况下可能有用。可以想象您可能希望获得一个字符串,其中equals
返回true
并且==
返回false
。调用new String(String)
将为您提供此功能。substring
、trim
和可能的其他String
方法会提供共享原始存储的字符串。在某些情况下,这可能导致内存泄漏。例如,调用new String(str.trim())
将防止出现内存泄漏,但代价是创建另一个已修剪的字符串的新副本。而String(String)
构造函数会保证分配一个新的支持数组以及为您提供一个新的String
对象。substring
和trim
的行为发生了变化。==
比较String
类型时的错误。 - Boris the SpidersubString
这样的操作在使用不到原始字符串一半的情况下返回具有新后备存储器的字符串,但在其他情况下借用原始字符串,或者在需要复制超过原始字符串寿命的情况和不需要的情况下分别使用单独的subString
方法,会对性能产生什么影响? - supercatsubstring
实现,共享数组和智能垃圾收集器,知道如何压缩这些字符串,如果原始大字符串变得不可访问。今天的JVM 有垃圾收集器,具有特殊的字符串和它们的字符数组知识,因为它将强制相等字符串的数组共享。尽管如此,拥有廉价的substring
也意味着每个String
都必须携带额外的offset
和length
字段,这些字段必须被每个其他字符串操作所尊重... - Holgerstring
作为语言中的不同类型,通常会保存引用,并允许强制转换为Object
或StringObject
,但将实现==
作为值相等,并且不保证(StringObject)string1 == (StringObject)string1
何时会为true或false [类似于例如(Short)x ==(Short)x
的情况]。这将允许实现有效地为不同种类的对象使用不同的... - supercatchar[]
、byte[]
或各种堆对象)并进行方便的替换。例如,ConcatenatedString
可以包含一个 String[]
,其第一个非空元素表示其内容,其余非空元素则标识组成部分。将 ConcatenatedString
用于需要线性字符串的任何目的都会导致系统物理上连接其片段并存储对线性字符串的引用(以防再次需要),但连接字符串然后将其连接到其他东西... - supercatchar[]
或 byte[]
来将它们合并而不是分别存储它们,但是没有理由一直重新生成大量的线性字符串。 - supercatnew
关键字时,您会明确地在堆上创建对象而不是常量池中。当在堆上创建对象时,没有办法共享该内存,并且它们变得完全陌生,不像常量池中那样。为了打破堆和常量池之间的障碍,字符串驻留
将帮助您解决问题。
请记住,常量池也是堆的一小部分,具有一些额外的好处,其中可用共享内存。字符串驻留是一种仅存储每个不同字符串值的一个副本的方法,该值必须是不可变的。
When you write
String str = new String("mystring");
String#intern
而不是new。String foo = "foo"; String bar = new String("foo").intern();
,那么bar == foo
,所以由new String("foo")
创建的实例不再被引用。 - Andy Turnernew String("foo")
创建的实例也不会引用它,并且将有资格进行垃圾回收。 - TheLostMind以下对象将被存储在字符串池中:
String s = "hello";
以下对象将存储在堆中(而不是字符串池中):
String s = new String ("hello")
s
指向此对象。在第二行,将构造一个新的String对象,并将常量String对象作为参数传递。https://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.5 - Joe强制进行垃圾回收!如果您只需要使用某个字符串一次,那么将其保留在内存中(几乎永远)就没有意义了。这种情况适用于常量池中的字符串。不在常量池中的字符串可以像其他对象一样被垃圾回收。因此,您应该只将经常使用的字符串放入常量池中(通过使用文字或将它们放入池中)。
String
与任何其他未使用的字符串一样,可能会被垃圾回收。只有当它们恰好与类文件中现有的常量匹配时,该常量才不会被回收,这并不是问题,因为它已经存在了。不使用intern()
在每个字符串上的主要原因是它不便宜,因为它将包含哈希和更糟糕的是,国际化字符串表的大小是固定的,这增加了冲突的可能性(在Java7u40之前,它的大小非常小)。 - Holgerintern()
视为相同的处理方式。调用intern()
不会突然修改类的字节码。被内部化但不匹配文字的字符串可以轻松进行垃圾回收。由new
创建的字符串是我们讨论的问题,因此我们不谈论文字。但是如果我们认为该字符串可能与文字匹配,则允许新字符串的垃圾回收是一个奇怪的论点,因为这意味着解决了一个本来不存在的问题,即当返回现有字符串并且没有创建新字符串时。 - Holgerintern()
方法所做的。 - Holger以字符串字面量形式创建的字符串(String s = "string";
)存储在字符串池中,但通过使用 new 调用 String 构造函数创建的字符串(String s = new String("string");
)不会存储在字符串池中。