为什么在Java中字符串是不可变的
Java中的String是不可变的,这使我们想到为什么将String类设计为不可变的决定。在这篇文章中,我们将了解做出此设计决定的一些原因。
Java String对象是不可变的
Java String类是不可变的,这意味着一旦创建String对象,就无法更改它。当我们使用诸如串联的String修改方法时,实际发生的情况是创建并返回了包含操作结果的新String。
例如,假设有String str
String str = “Hello”;
这意味着str指向存储值" Hello"的存储位置。
现在,如果我们将另一个值连接到此String并将其分配给相同的引用。由于String是不可更改的,因此无法修改原始字符串,因此这种串联意味着将使用修改后的值创建一个新的String对象,并且str开始指向该新对象。
str = str.concat(" World");
如我们所见,str现在引用修改后的对象,而旧对象未引用且准备好进行垃圾回收。
这是连接的另一个示例,但是返回的修改后的字符串未分配给任何变量。
public class StringLiteral { public static void main(String[] args) { String str = "Hello"; str.concat(" World"); System.out.println("Value- " + str); } }
输出:
Value- Hello
如我们所见,str仍然引用原始的String对象。
为什么字符串在Java中是不可变的
现在,当我们看到示例时,String是什么是不变的实际上意味着让我们看一下"为什么"部分。
1减少内存使用量–要了解String是不可变的,如何减少内存使用量,我们必须了解Java中的String池。
String是Java中的特殊类,也是最常用的类之一。这就是为什么使用常量字符串池的概念来最大程度地减少内存使用的原因。
每当创建任何String文字(用双引号引起来的String)时,JVM都会在String池中扫描具有相同值的任何String(如果返回相同的引用)。因此,不会为同一字符串分配新的内存,而是使用现有的内存。
让我们看一个例子。如果按照以下方式创建了三个字符串:
String str1 = “Hello”; String str2 = “Hello”; String str3 = “Hello”;
然后,所有三个对象都引用相同的内存。
现在假设str1的值已更改,如果原始字符串本身已更改,那么其他两个引用又如何呢?他们还将开始指向不正确的更改值。这就是为什么将String设置为不可变会确保无法修改原始对象的原因。
因为Java中的String是不可变的,所以可以对字符串进行池化,这就是该属性如何导致String减少内存使用的原因。
2线程安全性– Java中的字符串是不可变的,因此一旦创建就不能对其进行修改,这反过来意味着字符串可以安全地用于多线程环境中,而无需担心更改。
如果线程更改了共享字符串的值,那么即使创建了新的String,原始字符串也保持不变。
3 Hashcode缓存–可以解释为什么String在Java中不可变的另一个原因是,它使哈希码可以为String缓存。
由于字符串一旦创建便无法修改,因此一旦为任何字符串计算出的哈希码都可以缓存并重新使用。不需要重新计算该哈希码。这使得在基于哈希的数据结构(如HashMap)中将String用作键非常有效。