JavaSE笔记(1.3)集合-Set

前言

深入学习集合要结合底层实现源码

简介:
Set集合,基础自Collection。特征是插入无序,不可指定位置访问。
Set集合的实现类可说是基于Map集合去写的。通过内部封装Map集合来实现的比如HashSet内部封装了HashMap。
Set集合的数据库不能重复(== 或 eqauls)的元素
Set集合的常用实现类有 HashSet 、TreeSet 、LinkedHashSet

跟随大佬的脚步

Set

Set 注重独一无二的性质,该体系集合用于存储无序(存入和取出的顺序不一定相同)元素,值不能重复。
对象的相等性本质是对象hashCode 值(java 是依据对象的内存地址计算出的此序号)判断的,如果想要让两个不同的对象视为相等的,就必须覆盖 Object 的hashCode 方法和 equals 方法

在这里插入图片描述
可以看到Set接口的方法(是collection的子类):
在这里插入图片描述

Set接口有3个实现类:HashSet(Hash表)、TreeSet(二叉树)、LinkedHashSet(HashSet+LinkedHashMap)

HashSet集合(封装HashMap)

  • 底层数据结构是哈希表(是一个元素为链表的数组) + 红黑树

TreeSet集合(基于TreeMap实现)

  • 底层数据结构是红黑树(是一个自平衡的二叉树)
  • 保证元素的排序方式

LinkedHashSet集合(HashSet+LinkedHashMap)

  • 底层数据结构由哈希表(是一个元素为链表的数组)和双向链表组成

HashSet(Hash 表)

HashSet的要点

实现Set接口
不保证迭代顺序

允许元素为null

底层实际上是一个HashMap实例

非同步

初始容量非常影响迭代性能

HashSet封装HashMap实现
在这里插入图片描述
HashMap是映射,是键值对key-value,而HashSet添加元素不是键值对,实现方法就是创建一个final型object当做value
在这里插入图片描述看看添加元素add()方法:
在这里插入图片描述确实是key-value键值对,把元素e放在key位置,final型object放在value位置
元素不可重复

package com.company;
import java.util.HashSet;
import java.util.Set;
public class CollectionSet {
    public static void main(String[] args){
        Set<String> set=new HashSet<>();
        set.add("hello");
        set.add("hello");
        System.out.println(set.size());
    }
}

HashSet的元素个数为1
在这里插入图片描述
判断重复的底层是通过 == 或者 equals(可以查看源码)

hashSet的实现原理:
往Haset添加元素的时候,HashSet会先调用元素的hashCode方法得到元素的哈希值 , 然后通过元素 的哈希值经过移位等运算,就可以算出该元素在哈希表中 的存储位置。


情况1: 如果算出元素存储的位置目前没有任何元素存储,那么该元素可以直接存储到该位置上。


情况2:
如果算出该元素的存储位置目前已经存在有其他的元素了,那么会调用该元素的equals方法与该位置的元素再比较一次,如果equals返回的是true,那么该元素与这个位置上的元素就视为重复元素,不允许添加,如果equals方法返回的是false,那么该元素运行添加

缺陷在插入的是对象就没法去重

package com.company;
import com.company.entity.User;

import java.util.HashSet;
import java.util.Set;
public class CollectionSet {
    public static void main(String[] args){
        Set<User> set=new HashSet<>();
        User user1=new User("1","zhangsan");
        User user2=new User("1","zhangsan");
        System.out.println(user1==user2);
        System.out.println(user1.equals(user2));
        set.add(new User("1","zhangsan"));
        set.add(new User("1","zhangsan"));
        System.out.println(set.size());

    }
}

== 和 equals比较地址值,而new的两个对象不是同一个对象

在这里插入图片描述
可以通过重写equals和hashCode方法解决:
在我们编写的类User中hashCode和equals方法:

    @Override
    public int hashCode() {
        return super.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        return super.equals(obj);
    }

重写:

  @Override
    public int  hashCode() {
        return this.id;
    }

    @Override
    public boolean equals(Object object) {
        if (object!=null && object instanceof User){
            User user=(User)object;
            if (this.id == user.id && this.name == user.name)
                return true;
            else
                return false;
        }
        return false;
    }

再运行上面的方法:
在这里插入图片描述完成去重

操作HashSet就是在操作HashMap

TreeSet

功能基本和TreeMap相似

TreeSet的要点

实现NavigableSet接口

可以实现排序功能

底层实际上是一个TreeMap实例

非同步

基于TreeMap实现,特点:插入无序内部有序(内部是链表,用迭代器、foreach遍历)

        Set<Integer> set=new TreeSet<>();
        set.add(1);
        set.add(3);
        set.add(2);
        Iterator iterator=set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }

输出(int型按升序排序):
在这里插入图片描述
如果想插入自定义对象User:

        Set<User> userTreeSet=new TreeSet<>();
        userTreeSet.add(new User(1,"zhangsan"));
        userTreeSet.add(new User(3,"lisi"));
        userTreeSet.add(new User(2,"wangwu"));
        Iterator iteratorUser=userTreeSet.iterator();
        while (iteratorUser.hasNext()){
            System.out.println(iteratorUser.next());
        }

报错,User无法转换成Comparable
在这里插入图片描述
TreeMap中的compare方法:
在这里插入图片描述
需要在User类中重写CompareTo方法(implements Comparable):
User.java:

package com.company.entity;

public class User implements Comparable<User> {
    private int  id;
    private String name;

    public User() {
    }

    public User(int id, String name) {
        this.id = id;
        this.name = name;
    }


    @Override
    public int  hashCode() {
        return this.id;
    }

    @Override
    public boolean equals(Object object) {
        if (object!=null && object instanceof User){
            User user=(User)object;
            if (this.id == user.id && this.name == user.name)
                return true;
            else
                return false;
        }
        return false;
    }
    
    
	//根据id排序
    @Override
    public int compareTo(User user) {
        return this.id-user.id;
    }
}

完成根据id排序
在这里插入图片描述
TreeSet与TreeMap相似,可实现排序功能


LinkedHashSet(HashSet+LinkedHashMap)

LinkedHashSet的要点:
迭代是有序的
允许为null

底层实际上是一个HashMap+双向链表实例(其实就是LinkedHashMap)

非同步
性能比HashSet差一丢丢,因为要维护一个双向链表初始容量与迭代无关,LinkedHashSet迭代的是双向链表

跟HashSet、TreeSet一样,LinkedHashSet和LinkedHashMap相似(HashSet+双链表)
在这里插入图片描述LinkedHashSet继承自HashSet,它的添加、删除、查询等方法都是直接super的HashSet的,唯一的不同就是它使用LinkedHashMap存储元素
在这里插入图片描述
和LinkedHashMap相似,那么LinkedHashMap的插入排序和访问排序LinkedHashSet有吗?
可以看构造方法:

在这里插入图片描述
在这里插入图片描述没有对accessOrder(排序方式)的改变,即只能是默认值false,只有插入排序

     LinkedHashSet<Integer> set=new LinkedHashSet<>();
     set.add(1);
     set.add(4);
     set.add(2);
     Iterator<Integer> iterator = set.iterator();
     while (iterator.hasNext()) {
         System.out.println(iterator.next());
     }

在这里插入图片描述
LinkedHashSet基于HashSet+双链表,与LinkedHashMap相似,增删改数据快,查数据慢

总结

Set集合都是基于Map实现,大部分的性质都和Map一样,仅仅用处不同:存储序列数据,不用键值对

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值