Java 集合的那些事儿 (二)【奔跑吧!JAVA】

举报
franco52576 发表于 2021/06/27 18:22:27 2021/06/27
【摘要】 介绍Java中的set

上一篇文章中,主要介绍了集合中的各种LIst及其功能。

今天我们接着介绍一下同样非常重要的Set集合。

Set集合

扩展Collection接口
无序集合,不允许存放重复的元素;允许使用null元素
add()equals() hashCode() 方法添加了限制
HashSet
TreeSetSet的实现

HashSet 的后台有一个HashMap;初始化后台容量;只不过生成一个HashSet的话,系统只提供key的访问; 如果有两个Key重复,那么会覆盖之前的;

实现类 :

HashSetequals返回truehashCode返回相同的整数;哈希表;存储的数据是无序的。
LinkedHashSet
:此实现与HashSet的不同之外在于,后者维护着一个运行于所有条目的双重链接列表。存储的数据是有序的。

HashSet

HashSet类直接实现了Set接口,其底层其实是包装了一个HashMap去实现的。HashSet采用HashCode算法来存取集合中的元素,因此具有比较好的读取和查找性能。

HashSet的特征:

  • 不仅不能保证元素插入的顺序,而且在元素在以后的顺序中也可能变化(这是由HashSetHashCode存储对象(元素)决定的,对象变化则可能导致HashCode变化)
  • HashSet是线程非安全的
  • HashSet元素值可以为NULL

HashSet常用方法:

  • public boolean contains(Object o) :如果set包含指定元素,返回true
  • public Iterator iterator()返回set中元素的迭代器
  • public Object[] toArray() :返回包含set中所有元素的数组public Object[] toArray(Object[] a) :返回包含set中所有元素的数组,返回数组的运行时类型是指定数组的运行时类型
  • public boolean add(Object o) :如果set中不存在指定元素,则向set加入
  • public boolean remove(Object o) :如果set中存在指定元素,则从set中删除
  • public boolean removeAll(Collection c) :如果set包含指定集合,则从set中删除指定集合的所有元素
  • public boolean containsAll(Collection c) :如果set包含指定集合的所有元素,返回true。如果指定集合也是一个set,只有是当前set的子集时,方法返回true

实现Set接口的HashSet,依靠HashMap来实现的。 我们应该为要存放到散列表的各个对象定义hashCode()equals()

HashSetequalsHashCode

前面说过,Set集合是不允许重复元素的,否则将会引发各种奇怪的问题。那么HashSet如何判断元素重复呢?
HashSet
需要同时通过equalsHashCode来判断两个元素是否相等,具体规则是,如果两个元素通过equalstrue,并且两个元素的hashCode相等,则这两个元素相等(即重复)。
所以如果要重写保存在HashSet中的对象的equals方法,也要重写hashCode方法,重写前后hashCode返回的结果相等(即保证保存在同一个位置)。所有参与计算 hashCode() 返回值的关键属性,都应该用于作为 equals() 比较的标准。
试想如果重写了equals方法但不重写hashCode方法,即相同equals结果的两个对象将会被HashSet当作两个元素保存起来,这与我们设计HashSet的初衷不符(元素不重复)。
另外如果两个元素哈市Code相等但equals结果不为trueHashSet会将这两个元素保存在同一个位置,并将超过一个的元素以链表方式保存,这将影响HashSet的效率。
如果重写了equals方法但没有重写hashCode方法,则HashSet可能无法正常工作,比如下面的例子。

import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

public class R {
    private int count;

    public R(int count) {
        this.count = count;
    }

    @Override
    public String toString() {
          return "R{" + "count=" + count + " # hashCode=" + this.hashCode() + '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        R r = (R) o;
        return count == r.count;
    }

//    @Override
//    public int hashCode() {
//        return Objects.hash(count);
//    }

    public static void main(String[] args) {
        Set set = new HashSet();
        set.add(new R(5));
        set.add(new R(-3));
        set.add(new R(9));
        set.add(new R(-2));
        System.out.println(set.contains(new R(-3)));
        System.out.println(set);

    }
}

上面注释了hashCode方法,所以你将会看到下面的结果。

false

[R{count=9 # hashCode=2003749087}, R{count=5 # hashCode=1283928880}, R{count=-3 # hashCode=295530567}, R{count=-2 # hashCode=1324119927}]

取消注释,则结果就正确了

true

[R{count=5 # hashCode=36}, R{count=9 # hashCode=40}, R{count=-3 # hashCode=28}, R{count=-2 # hashCode=29}]

TreeSet类的特征

TreeSet实现了SortedSet接口,顾名思义这是一种排序的Set集合,查看jdk源码发现底层是用TreeMap实现的,本质上是一个红黑树原理。 正因为它是排序了的,所以相对HashSet来说,TreeSet提供了一些额外的按排序位置访问元素的方法,例如first(), last(), lower(), higher(), subSet(), headSet(), tailSet().
TreeSet
的排序分两种类型,一种是自然排序,另一种是定制排序。

自然排序(在元素中写排序规则)

TreeSet 会调用compareTo方法比较元素大小,然后按升序排序。所以自然排序中的元素对象,都必须实现了Comparable接口,否则会抛出异常。对于TreeSet判断元素是否重复的标准,也是调用元素从Comparable接口继承而来额compareTo方法,如果返回0则是重复元素(两个元素I相等)。Java的常见类都已经实现了Comparable接口,

【奔跑吧!JAVA】有奖征文火热进行中:https://bbs.huaweicloud.com/blogs/265241

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。