Java HashMap 和 TreeMap 的区别?

在 Java 集合框架中,HashMap 和 TreeMap 是两种常用的 Map 实现,它们有各自的特点和使用场景。理解它们的区别对于高效使用这两种数据结构至关重要。本篇博客将通过源码解读的方式详细解析 HashMap 和 TreeMap 的区别,并结合实际案例说明它们的应用场景。

类继承关系与接口实现

首先,我们来看一下 HashMap 和 TreeMap 的类继承关系:

java

public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable

public class TreeMap<K,V> extends AbstractMap<K,V>
    implements NavigableMap<K,V>, Cloneable, Serializable

从类继承关系可以看出,HashMap 和 TreeMap 都继承自 AbstractMap,但 TreeMap 还实现了 NavigableMap 和 SortedMap 接口。

NavigableMap 接口

实现 NavigableMap 接口让 TreeMap 具有对集合内元素进行搜索的能力。NavigableMap 提供了丰富的方法来操作键值对:

  • 定向搜索:

    java

    Entry<K,V> ceilingEntry(K key);
    Entry<K,V> floorEntry(K key);
    Entry<K,V> higherEntry(K key);
    Entry<K,V> lowerEntry(K key);

    这些方法用于定位大于、小于、大于等于、小于等于给定键的最接近的键值对。

  • 子集操作:

    java

    NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive);
    NavigableMap<K,V> headMap(K toKey, boolean inclusive);
    NavigableMap<K,V> tailMap(K fromKey, boolean inclusive);

    这些方法可以高效地创建原集合的子集视图,而无需复制整个集合。

  • 逆序视图:

    java

    NavigableMap<K,V> descendingMap();

    返回一个逆序的 NavigableMap 视图,可以反向迭代整个 TreeMap

  • 边界操作:

    java

    Entry<K,V> firstEntry();
    Entry<K,V> lastEntry();
    Entry<K,V> pollFirstEntry();
    Entry<K,V> pollLastEntry();

    这些方法方便地访问和移除元素。

SortedMap 接口

实现 SortedMap 接口让 TreeMap 具有对集合中的元素根据键排序的能力。默认情况下,TreeMap 按照键的自然顺序(升序)排序,但也可以指定排序的比较器。

java

TreeMap<Person, String> treeMap = new TreeMap<>(new Comparator<Person>() {
    @Override
    public int compare(Person person1, Person person2) {
        int num = person1.getAge() - person2.getAge();
        return Integer.compare(num, 0);
    }
});
实例代码

java

public class Person {
    private Integer age;

    public Person(Integer age) {
        this.age = age;
    }

    public Integer getAge() {
        return age;
    }

    public static void main(String[] args) {
        TreeMap<Person, String> treeMap = new TreeMap<>(new Comparator<Person>() {
            @Override
            public int compare(Person person1, Person person2) {
                int num = person1.getAge() - person2.getAge();
                return Integer.compare(num, 0);
            }
        });

        treeMap.put(new Person(3), "person1");
        treeMap.put(new Person(18), "person2");
        treeMap.put(new Person(35), "person3");
        treeMap.put(new Person(16), "person4");

        treeMap.entrySet().stream().forEach(entry -> {
            System.out.println(entry.getValue());
        });
    }
}

输出结果:

txt

person1
person4
person2
person3

可以看出,TreeMap 中的元素已经按照 Person 的 age 字段的升序排列了。

Lambda 表达式实现

上面的 Comparator 可以用 Lambda 表达式简化:

java

TreeMap<Person, String> treeMap = new TreeMap<>((person1, person2) -> {
    int num = person1.getAge() - person2.getAge();
    return Integer.compare(num, 0);
});
HashMap vs TreeMap

1. 数据结构:

  • HashMap 使用哈希表实现,基于散列函数。
  • TreeMap 使用红黑树实现,保证键的有序性。

2. 性能:

  • HashMap 的插入、删除和查找操作平均时间复杂度为 O(1)。
  • TreeMap 的插入、删除和查找操作时间复杂度为 O(log n),因为红黑树需要保持平衡。

3. 有序性:

  • HashMap 不保证键的顺序。
  • TreeMap 保证键的自然顺序,或者通过指定的比较器进行排序。

4. Null 键和 Null 值:

  • HashMap 允许一个 Null 键和多个 Null 值。
  • TreeMap 不允许 Null 键,但允许 Null 值。

5. 应用场景:

  • 使用 HashMap 在需要快速访问键值对且不关心顺序时。
  • 使用 TreeMap 在需要按键排序或者需要范围搜索操作时。
总结

HashMap 和 TreeMap 各有优劣,选择它们取决于具体的应用场景和需求。通过理解它们的实现细节和性能特点,我们可以更有效地利用这两种数据结构来解决实际问题。

  • 23
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值