Collection集合框架当中的Set接口

Collection集合框架当中的Set接口


前言

Set集合继承Colletion 可使用Colletion的常用方法
Collection集合的常用方法
boolean add(E e) 向集合中添加元素
boolean remove(E e) 将元素从集合中删除
void clear() 清空集合所有的元素
boolean isEmpty() 判断集合是否为空
int size() 获取集合的长度
boolean contains(E e) 判断集合中是否包含指定的元素

Set接口的具体实现:

TreeSet集合、HashSet集合(无序集合没有重复元素)、LinkedHashSet集合)

特点:
1、不允许元素重复
2、没有索引,没有带索引的方法

一、HashSet集合

数据结构:哈希表
1、无序集合,存取顺序可能不一致
2、无重复元素
3、没有索引
4、底层是一个哈希表结构,查询的速度非常的快

HashSet是怎么保证不存入重复元素的

1.根据对象的哈希值计算存储位置,如果当前位置没有元素则直接存入
如果当前位置有元素存在,则进入第二步。
2.当前元素的元素和已经存在的元素比较哈希值,如果哈希值不同则
将当前元素进行存储,如果哈希值相同,则进入第三步。
3.通过equals()方法比较两个元素的内容,如果内容不相同,则将当前
元素进行存储,如果内容相同,则不存储当前元素。
public class Demo1HashSet {
    public static void main(String[] args) {
        HashSet<String> set=new HashSet<>();
        String str="abc";
        String str2="abc";
        set.add(str);
        //得到str的哈希值,发现无重复直接添加进集合
        set.add(str2);
        //add首先进行哈希值的比较,发现哈希值相同就会掉头equals方法ste.equals(str2)返回trun
        //即不存储str2
        set.add("通话");
        set.add("重地");
        System.out.println("通话".hashCode()+"====="+"重地".hashCode());
        //add调用hashCode发现两个元素的哈希值相等,然后进行equals内容比较
        //返回false,即任然存储“重地”
        System.out.println(set);
    }
}
DataResult:
1179395=====1179395
[通话, 重地, abc]

数据结构:
JDK8之前: 哈希表(数组 + 链表)
JDK8之后: 哈希表(数组 + 链表 + 红黑树)
哈希表的特点:速度快
数据结构:把元素进行分组(相同哈希值的元素在一组),然后使用链表或者红黑树有将相同哈希值的元素连接到一起。

注意:同一数组索引位置的链表元素超过8位就会转换成红黑树

如果了解HashMap的小伙伴可能会疑问,怎么底层数据结构跟HashMap一样,如果你打开了源码你会发现,它其实是HashMap集合来存储的。

底层无参构造初始化

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

HashSet存储自定义类型(例如:Person)的元素时必要重写hashCode和equals方法

应用实列:

public class Demo2HashSetStudentType {
    private  String name;
    private int age;
    public Demo2HashSetStudentType(){

    }

    public Demo2HashSetStudentType(String name,int age) {
        this.name = name;
        this.age=age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Demo2HashSetStudentType{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';

    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Demo2HashSetStudentType that = (Demo2HashSetStudentType) o;
        return age == that.age &&
                Objects.equals(name, that.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

    public static void main(String[] args) {
        Demo2HashSetStudentType one=new Demo2HashSetStudentType("Arvin",21);
        Demo2HashSetStudentType two=new Demo2HashSetStudentType("Arvin",21);
        Demo2HashSetStudentType three=new Demo2HashSetStudentType("Arvin",20);
        HashSet<Demo2HashSetStudentType> set=new HashSet<>();
        set.add(one);
        set.add(two);
        set.add(three);
        //输出set集合发现重复
        System.out.println(set);
        //查看hashCode和equals结果
        System.out.println(one.hashCode());
        System.out.println(two.hashCode());
        System.out.println(one==two);
        System.out.println(one.equals(two));
        //发现哈希值不同但是equals方法比较的是地址,返回值是false,所以要重写equals方法
    }
}
DataResult:
[Demo2HashSetStudentType{name='Arvin', age=20}, Demo2HashSetStudentType{name='Arvin', age=21}]
1969796844
1969796844
false
true

二、哈希值

十进制的整数,由系统随机给出的(就是对象的地址,是一个逻辑地址,一个模拟出来的地址)
不是实际存储的物理地址
在Object类有一个方法,可以获取对象的哈希值

int hashCode();返回对象的哈希值

方法源码:

public native int hashCode();native代表该方法调用本地操作系统的方法 特殊的哈希值:

1、String类哈希值:重写了hashCode方法
java.lang.String 类 已经重写了父类java.lang.Object的hashCode()方法
所以对于"str".hashCode() 的返回值无论运行多少次都一样。

public class Demo4HashCode {
    public static void main(String[] args) {

        //对于重写hashcode方法的特殊String
        String str=new String("Arvin");
        String str2=new String("Arvin");
        System.out.println(str.hashCode());
        System.out.println(str2.hashCode());
        System.out.println("吃饭".hashCode());
        System.out.println("睡觉".hashCode());

    }
}
DataResult:
63541802
63541802
705994
982664

三、LinkedHashSet

LinkedHashSet extends HashSet

特点:底层是一个哈希表(数组+链表/红黑树)+链表;多了一条链表(存储元素的顺序)保证元素的有序性。

public class Demo3LinkedHashSet {
    public static void main(String[] args) {
        //HashSet集合底层是一个哈希表,无序不可重复
        HashSet<Integer> hash=new HashSet<>();
        hash.add(2);
        hash.add(1);
        hash.add(3);
        hash.add(3);
        System.out.println(hash);
        //LinkedHashSet底层是一个哈希表和一个链表,双链表,其中一个存储元素顺序
        //不可重复,但是有序
        LinkedHashSet<Integer> linked=new LinkedHashSet<>();
        linked.add(2);
        linked.add(1);
        linked.add(2);
        linked.add(3);
        System.out.println(linked);

    }
}
DataResult:
[1, 2, 3]
[2, 1, 3]

四、TreeSet

TreeSet集合的特点

1.元素有序。元素可以按照一定规则进行排序。具体要取决于构造方法

new TreeSet():根据元素的自然顺序进行排序

new TreeSet(Comparator c):根据指定的比较器进行排序

2.TreeSet集合没有索引。只能通过迭代器、增强for循环进行遍历
3.TreeSet集合不能存储重复元素

无参构造底层:

 public TreeSet() {
        this(new TreeMap<E,Object>());
    }

实列

  public static void main(String[] args) {
        TreeSet<Integer> set = new TreeSet<>();
        set.add(1);
        set.add(2);
        set.add(3);
        set.add(4);

        for (Integer integer : set) {
            System.out.println(integer);
        }
    }

结果:

1
2
3
4

有参构造传入 指定的比较器之后:
降序排序

 TreeSet<Integer> set = new TreeSet<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1; //降序排序
            }
        });
        set.add(1);
        set.add(2);
        set.add(3);
        set.add(4);

        for (Integer integer : set) {
            System.out.println(integer);
        }
    }

4 3 2 1

相关推荐
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页