Java HashMap 和 HashSet 区别?

在 Java 中,HashMap 和 HashSet 都是非常常用的集合类。尽管它们在使用上有些相似,但它们的内部实现和应用场景有明显的区别。本文将深入解析 HashMap 和 HashSet 的实现细节,并通过源码分析和实际案例来详细说明它们的不同。

基本概念

HashMap

HashMap 是 Java 集合框架中的一个类,它实现了 Map 接口。它用于存储键值对,并允许快速地根据键检索值。它的主要特点包括:

  • 键值对存储:每个元素都是一个键值对。
  • 允许一个 null 键和多个 null 值
  • 无序:元素没有特定的顺序。

HashSet

HashSet 是 Java 集合框架中的一个类,它实现了 Set 接口。它用于存储唯一的对象,并且不允许存储重复的元素。它的主要特点包括:

  • 唯一性:集合中的每个元素都是唯一的。
  • 不允许存储 null 元素(在某些情况下)。
  • 无序:元素没有特定的顺序。

底层实现

HashSet 底层基于 HashMap 实现

HashSet 的实现非常简单,因为它直接利用了 HashMap 的内部机制。HashSet 内部维护了一个 HashMap 实例,并且所有操作都是通过这个 HashMap 实现的。下面是 HashSet 的部分源码:

java

public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable {
    private transient HashMap<E,Object> map;

    // Dummy value to associate with an Object in the backing Map
    private static final Object PRESENT = new Object();

    public HashSet() {
        map = new HashMap<>();
    }

    public boolean add(E e) {
        return map.put(e, PRESENT) == null;
    }
    
    // Other methods are omitted for brevity
}

从上面的源码可以看出,HashSet 通过一个 HashMap 实例 map 来存储元素。HashSet 的 add 方法实际上是调用 HashMap 的 put 方法来实现的,只不过它将所有的值都映射到一个固定的对象 PRESENT 上。

HashMap 的内部实现

HashMap 的实现相对复杂,它通过一个数组和链表的结合来实现。主要的数据结构如下:

  • 数组:用于存储 HashMap 的桶(bucket)。
  • 链表:用于处理哈希冲突(即不同的键计算出的哈希值相同)。

以下是 HashMap 的核心部分源码:

java

public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable {
    // Initial capacity and load factor
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
    static final float DEFAULT_LOAD_FACTOR = 0.75f;

    // The array of bins.
    transient Node<K,V>[] table;

    // Initialize the table
    void resize() {
        ...
    }

    // Hash function
    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

    // Add a new entry
    final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
        ...
    }

    public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

    // Other methods are omitted for brevity
}

在上面的代码中,HashMap 通过 table 数组来存储桶,每个桶可能包含多个节点(通过链表链接)。哈希函数 hash 用于计算键的哈希值,而 putVal 方法用于将键值对添加到 HashMap 中。

具体区别

接口实现

  • HashMap 实现了 Map 接口,存储的是键值对。
  • HashSet 实现了 Set 接口,存储的是对象。

存储结构

  • HashMap 存储的是键值对,允许一个 null 键和多个 null 值。
  • HashSet 仅存储对象,不允许存储重复的对象。

添加元素

  • HashMap 使用 put 方法添加元素。
  • HashSet 使用 add 方法添加元素。

哈希计算

  • HashMap 使用键来计算哈希值。
  • HashSet 使用对象本身来计算哈希值。

实际案例及应用场景

HashMap 应用场景

  1. 快速查找:例如,在实现缓存系统时,使用 HashMap 可以快速地根据键检索到缓存的值。
  2. 统计频率:在文本处理或数据分析中,使用 HashMap 可以统计单词或其他元素的频率。

HashSet 应用场景

  1. 去重:在处理数据时,使用 HashSet 可以快速去重,例如从一个列表中去除重复的元素。
  2. 集合操作HashSet 可以用于实现集合的交集、并集等操作。
  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. HashMap 和 Hashtable 的区别 HashMap 和 Hashtable 都是用于存储键值对的集合类,它们之间的区别如下: - 线程安全性:Hashtable 是线程安全的,而 HashMap 是非线程安全的,如果需要在多线程环境下使用 HashMap,需要保证线程同步。 - null 值:Hashtable 不允许键或值为 null,而 HashMap 允许键或值为 null。 - 继承关系:Hashtable 是早期 Java 类库中的类,而 HashMapJava 1.2 之后引入的类,它继承了 AbstractMap 类。 2. HashMapHashSet区别 HashMapHashSet 都是用于存储元素的集合类,它们之间的区别如下: - 存储方式:HashMap 存储键值对,而 HashSet 存储唯一的元素。 - 底层实现:HashMap 是基于哈希表实现的,而 HashSet 是基于 HashMap 实现的(底层使用 HashMap 存储元素)。 3. HashMap 和 TreeMap 的区别 HashMap 和 TreeMap 都是用于存储键值对的集合类,它们之间的区别如下: - 存储方式:HashMap 是基于哈希表实现的,而 TreeMap 是基于红黑树实现的,因此 TreeMap 可以对元素进行排序。 - 性能:HashMap 的插入和查找操作的时间复杂度都是 O(1),而 TreeMap 的插入和查找操作的时间复杂度都是 O(log n),因此 HashMap 的性能比 TreeMap 更高效。 - 排序:HashMap 不支持对元素进行排序,而 TreeMap 可以对元素进行排序。 总的来说,HashMapHashSet 都是非常常用的集合类,在实际开发中需要根据具体的需求选择使用哪种集合类。而 TreeMap 则适用于需要对元素进行排序的场景。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值