35. List、Set、Map 之间的区别是什么?
List、Set 和 Map 是 Java 中 Collection Framework 中的三大接口,它们用于存储集合数据,但是它们之间有着明显的区别:
-
List(列表):
-
List 是一个有序集合,它允许元素重复。
-
它维护了元素插入的顺序,可以通过索引(基于0的整数)访问。
-
List 接口的常用实现类包括 ArrayList、LinkedList 和 Vector。
-
示例代码:
List<String> list = new ArrayList<>(); list.add("Apple"); list.add("Banana"); list.add("Apple"); System.out.println(list.get(1)); // 输出 "Banana"
-
-
Set(集):
-
Set 是一个无序集合,它不允许元素重复。
-
它不保证元素的顺序,且不允许通过索引访问。
-
Set 接口的常用实现类包括 HashSet、LinkedHashSet 和 TreeSet。
-
示例代码:
Set<String> set = new HashSet<>(); set.add("Apple"); set.add("Banana"); set.add("Apple"); System.out.println(set); // 输出可能不包含重复的 "Apple"
-
-
Map(映射):
-
Map 是一个键值对的集合,它通过键来存储元素,并且键是唯一的。
-
每个键对应一个值,键和值可以是任意类型。
-
它不保证元素的顺序,且不支持索引访问。
-
Map 接口的常用实现类包括 HashMap、LinkedHashMap 和 TreeMap。
-
示例代码:
Map<String, Integer> map = new HashMap<>(); map.put("Apple", 1); map.put("Banana", 2); map.put("Apple", 3); // 更新键 "Apple" 的值 System.out.println(map.get("Apple")); // 输出 3
-
下面是一个简单的区别表格:
特性 | List | Set | Map |
---|---|---|---|
是否有序 | 是 | 否(TreeSet 例外) | 否 |
是否允许重复元素 | 是 | 否 | 键不允许重复,值可以 |
元素访问方式 | 通过索引 | 不支持索引 | 通过键 |
常用实现类 | ArrayList, LinkedList | HashSet, TreeSet | HashMap, TreeMap |
理解这三个接口的区别对于设计有效的数据结构至关重要。
36. HashMap 和 Hashtable 有什么区别?
HashMap 和 Hashtable 是 Java 中两种常用的基于哈希表的 Map 实现方式,用于存储键值对。它们之间的主要区别如下:
- 同步性:Hashtable 是同步的,也就是说它所有的公共方法都是线程安全的,而 HashMap 不是。因此,如果有多个线程访问同一个哈希表,并且至少有一个线程在结构上修改了映射,则必须保持外部同步。对于不需要线程安全的场合,HashMap 性能会更好。
- null 值:HashMap 允许将 null 作为键和值,而 Hashtable 不允许键或值为 null。如果尝试将 null 作为键或值放入 Hashtable 中,它会抛出 NullPointerException。
- 迭代器:HashMap 提供了 fail-fast 迭代器,而 Hashtable 提供的是 Enumerator。Fail-fast 迭代器在创建迭代器之后,如果结构上对映射进行修改(除了通过迭代器自己的 remove 方法),迭代器会快速失败抛出 ConcurrentModificationException。
- 继承的类:Hashtable 继承自 Dictionary 类,而 HashMap 继承自 AbstractMap 类。这反映了它们设计上的不同,Hashtable 更老一些,是 Java 早期版本的一部分。
- 方法和实现:由于 HashMap 继承自 AbstractMap,因此它提供了额外的抽象方法,比如
putAll(Map<? extends K, ? extends V> m)
和remove(Object key)
,而 Hashtable 没有这些。
以下是一个简单的对比表格:
特性/类 | HashMap | Hashtable |
---|---|---|
同步性 | 非线程安全 | 线程安全 |
Null 值 | 允许键和值为 null | 不允许键或值为 null |
迭代器 | fail-fast 迭代器 | Enumerator |
继承 | AbstractMap | Dictionary |
方法差异 | 提供额外的 Map 方法 | 提供较少的额外方法 |
示例代码:
// 使用 HashMap
Map<String, String> hashMap = new HashMap<>();
hashMap.put(null, "value1");
hashMap.put("key2", null);
System.out.println(hashMap.get(null)); // 输出 "value1"
// 使用 Hashtable
Map<String, String> hashtable = new Hashtable<>();
// 下面这行会抛出 NullPointerException
// hashtable.put(null, "value1");
// 下面这行也会抛出 NullPointerException
// hashtable.put("key2", null);
以上示例简单展示了如何在代码中使用 HashMap 和 Hashtable,并展示了它们在处理 null 值时的不同行为。
领【150 道精选 Java 高频面试题】请go公众号:码路向前 。