上一篇地址:赶紧收藏!2024 年最常见 100道 Java 基础面试题(十)-CSDN博客
二十一、HashMap
和Hashtable
有什么区别?
HashMap
和Hashtable
都是Java中实现散列表(hash table)的类,它们用于存储键值对映射。尽管它们的实现细节相似,但是存在一些关键的区别:
-
同步性:
Hashtable
是线程安全的,它的所有方法都是同步的,这意味着在多线程环境下,Hashtable
能够保证数据的一致性。HashMap
在Java 7及以前的版本中不是线程安全的。从Java 8开始,虽然HashMap
本身不是线程安全的,但是它提供了一些方法(如computeIfAbsent()
)来支持并发操作。通常,为了线程安全,可以使用ConcurrentHashMap
作为替代。
-
null键和值:
Hashtable
不允许使用null
作为键(key)或值(value)。HashMap
允许一个null
键和多个null
值。
-
继承:
Hashtable
继承自Dictionary
类,这是一个古老的类,现在已经不推荐使用。HashMap
实现了Map
接口,并且可以作为Map
接口的实现来使用。
-
性能:
- 由于同步的开销,
Hashtable
在单线程环境下的性能通常不如HashMap
。 - 在单线程环境下,如果不需要线程安全的集合,推荐使用
HashMap
。如果需要线程安全的集合,可以考虑使用Collections.synchronizedMap()
包装一个HashMap
,或者使用ConcurrentHashMap
。
- 由于同步的开销,
-
遍历方式:
Hashtable
和HashMap
都允许使用迭代器来遍历它们的键和值。不过,由于Hashtable
较老,它的遍历方式可能与HashMap
略有不同。
-
遗留代码:
Hashtable
是一个遗留类,它的存在主要是为了兼容旧的代码。新的代码通常推荐使用HashMap
或ConcurrentHashMap
。
示例代码:
import java.util.HashMap;
import java.util.Hashtable;
public class HashMapVsHashtable {
public static void main(String[] args) {
// HashMap示例
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put(null, "nullValue"); // 可以存储null键
System.out.println(hashMap.get(null)); // 输出"nullValue"
// Hashtable示例
Hashtable<String, String> hashtable = new Hashtable<>();
// hashtable.put(null, "nullValue"); // 这将抛出NullPointerException
System.out.println(hashtable.get("key")); // 输出null,因为没有为"key"设置值
}
}
总结:
HashMap
和Hashtable
在功能上相似,但是它们在同步性、对null
值的支持、性能和使用场景上有所不同。- 在大多数情况下,应该优先使用
HashMap
,并且如果需要线程安全的集合,则使用ConcurrentHashMap
或通过Collections.synchronizedMap()
包装的HashMap
。
二十二、如何决定使用HashMap
还是TreeMap
?
HashMap
和TreeMap
都是Java中实现Map
接口的类,它们都用于存储键值对映射,但是它们在内部实现、性能特性和使用场景上有所不同:
-
内部实现:
HashMap
是基于哈希表的数据结构,它使用哈希函数将键映射为数组的索引,从而访问和存储数据。TreeMap
是基于红黑树的数据结构,它将键值对按照键的自然顺序或提供的Comparator
顺序进行排序。
-
性能特性:
HashMap
提供更快的访问速度,因为哈希表可以提供常数时间的查找、插入和删除操作(平均情况下)。TreeMap
提供有顺序的数据访问,但是查找、插入和删除操作的时间复杂度为O(log n)
,比HashMap
慢。
-
键的顺序:
HashMap
不保证键的顺序,键的存储和迭代顺序可能取决于哈希函数的实现。TreeMap
保证了键的顺序,要么是自然排序顺序,要么是构造时提供的Comparator
顺序。
-
空键(null key)和空值(null value):
HashMap
允许一个空键和多个空值。TreeMap
不允许空键,但可以有一个空值。
-
使用场景:
- 当需要快速查找、插入和删除操作,且不关心键的顺序时,应该使用
HashMap
。 - 当需要按键的顺序遍历键值对,或者需要保持键的排序时,应该使用
TreeMap
。
- 当需要快速查找、插入和删除操作,且不关心键的顺序时,应该使用
-
线程安全性:
- 两者都不是线程安全的。如果需要线程安全的实现,可以使用
Collections.synchronizedMap()
来包装HashMap
或TreeMap
,或者使用ConcurrentHashMap
。
- 两者都不是线程安全的。如果需要线程安全的实现,可以使用
示例代码:
import java.util.HashMap;
import java.util.TreeMap;
public class HashMapVsTreeMap {
public static void main(String[] args) {
// HashMap示例
HashMap<Integer, String> hashMap = new HashMap<>();
hashMap.put(1, "Java");
hashMap.put(2, "Python");
hashMap.put(null, "Null Key"); // HashMap允许null键和null值
// TreeMap示例
TreeMap<Integer, String> treeMap = new TreeMap<>();
treeMap.put(1, "Java");
treeMap.put(2, "Python");
// treeMap.put(null, "Null Key"); // TreeMap不允许null键,但允许null值
// HashMap的迭代顺序可能依赖于哈希函数的实现,而TreeMap的迭代顺序是按键的自然顺序
}
}
总结:
- 选择
HashMap
还是TreeMap
取决于应用场景的需求。如果需要快速的搜索且键的顺序不重要,则使用HashMap
。 - 如果需要按键的自然顺序或特定顺序遍历键值对,则使用
TreeMap
。 - 考虑线程安全性时,可以使用
ConcurrentHashMap
或通过Collections.synchronizedMap()
包装的Map
实现。