String 不可变的好处包括可以缓存 hash 值
在 Java 中,String
类是不可变的,这意味着一旦创建了一个字符串对象,它的内容就不能被修改。这个特性带来了很多好处,其中之一就是可以缓存字符串的哈希值。
考虑以下示例:
import java.util.HashMap;
import java.util.Map;
public class StringHashCachingExample {
public static void main(String[] args) {
Map<String, Integer> wordFrequency = new HashMap<>();
String[] words = {"hello", "world", "java", "hello", "java"};
for (String word : words) {
Integer count = wordFrequency.get(word);
if (count == null) {
count = 0;
}
wordFrequency.put(word, count + 1);
}
System.out.println(wordFrequency);
}
}
在这个示例中,我们使用一个 HashMap
来存储每个单词出现的频率。当我们需要查询或插入一个单词时,HashMap
会根据该单词的哈希值来确定其在内部存储结构中的位置。
由于 String
是不可变的,所以它的哈希值在创建后就不会改变。这使得 String
类可以缓存其哈希值。当我们使用 String
作为 HashMap
的键时,这个特性可以提高性能,因为我们不需要每次访问 HashMap
时都重新计算哈希值。相反,我们可以直接使用缓存的哈希值,从而减少计算开销。
如果 String
类是可变的,那么我们无法缓存哈希值,因为每次修改字符串时,其哈希值可能会发生变化。这将导致每次访问 HashMap
时都需要重新计算哈希值,增加计算开销,降低性能。
总之,String
类的不可变特性使得我们可以缓存哈希值,从而提高在使用哈希表(如 HashMap
和 HashSet
)时的性能。这是 String
不可变性的一个重要好处。
HashMap是如何帮我们缓存哈希值的呢?
实际上,HashMap
不直接缓存哈希值,而是 String
类本身在内部缓存了哈希值。在 String
类中,有一个名为 hash
的私有字段,用于存储字符串的哈希值。当我们首次调用 hashCode()
方法时,会计算哈希值并将其存储在 hash
字段中。之后,每次调用 hashCode()
时,都会直接返回缓存的哈希值,而不是重新计算。
以下是 String
类中 hashCode()
方法的源码(JDK 8 中的实现):
private int hash; // 默认为 0
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
可以看到,hashCode()
方法首先检查 hash
字段是否为 0,如果为 0,则计算哈希值并将其存储在 hash
字段中;如果不为 0,直接返回 hash
字段的值。由于 String
是不可变的,所以一旦计算了哈希值,就不会发生改变。
当我们使用 HashMap
时,需要计算键的哈希值来确定在内部存储结构中的位置。当我们使用 String
作为键时,HashMap
会调用 String
类的 hashCode()
方法来获取哈希值。由于 String
类已经缓存了哈希值,所以这个过程非常高效,不需要每次都重新计算哈希值。
这里要强调的是,HashMap
并没有直接帮助我们缓存哈希值,而是 String
类本身在内部缓存了哈希值。当我们使用 String
作为 HashMap
的键时,可以直接利用这个缓存的哈希值,从而提高性能。