0061 Set接口

 

 

 

 

 

  

 

 

 

 

 

 

 

 

 

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

/*
    Set接口
    1.无序(添加和取出的顺序不一样),没有索引
    2.不允许重复元素,最多包含一个null
    3.实现类主要有 TreeSet,HashSet....

    常用方法
    Set接口也是Collection的子接口,因此方法和Collection接口一样

    遍历方式(不能使用索引的方式来获取)
    1.使用迭代器
    2.增强for
 */
@SuppressWarnings({"all"})
public class Set_ {
    public static void main(String[] args) {
        Set set = new HashSet();//以Set接口的实现类HashSet来演示方法
        set.add("john");
        set.add("lucy");
        set.add("john");//重复
        set.add("jack");
        set.add("mary");
        set.add(null);//
        set.add(null);// 再次添加 null
        //存放无序,且不允许重复元素,最多包含一个null
        System.out.println("set=" + set);//set=[null, mary, john, lucy, jack]

        //遍历
        System.out.println("=====使用迭代器=====");
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            Object obj = iterator.next();
            System.out.println("obj=" + obj);
        }

        System.out.println("=====增强for=====");
        for (Object obj : set) {
            System.out.println("obj=" + obj);
        }
    }
}
import java.util.HashSet;

/*
     HashSet
     1.HashSet实现了Set接口
     2.HashSet实际上是HashMap
     3.可以存放null,但最多只能存放一个,不能有重复元素
     4.HashSet不保证元素是有序的

 */
@SuppressWarnings({"all"})
public class Set02 {
    public static void main(String[] args) {
        HashSet hashSet = new HashSet();
    /*      构造器源码
            public HashSet() {
                map = new HashMap<>();
            }HashSet实际上是HashMap
    */
        hashSet.add(null);
        hashSet.add(null);
        //可以存放null,但最多只能存放一个,不能有重复元素
        System.out.println(hashSet);//[null]

        HashSet set = new HashSet();
        set.add("lucy");
        set.add("lucy");
        set.add(new Dog("tom"));
        set.add(new Dog("tom"));//添加成功
        System.out.println("set=" + set);//set=[tom, tom, lucy]

        set.add(new String("huang"));
        set.add(new String("huang"));//添加失败-->底层机制
        System.out.println("set=" + set);//set=[tom, tom, lucy, huang]
    }
}

class Dog {
    private String name;
    public Dog(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return name;
    }
}
/*
    HashSet底层是HashMap,HashMap底层是(数组+链表+红黑树)
 */
//模拟底层 数组+链表结构
@SuppressWarnings({"all"})
public class Set03 {
    public static void main(String[] args) {
        //创建数组,类型Node[]
        Node[] table = new Node[16];
        System.out.println(table);
        //创建结点
        Node node1 = new Node("jack", null);
        table[2] = node1;//把node1放到table表索引为2的位置
        Node node2 = new Node("mary", null);
        node1.next = node2;//将node1结点挂载到node2
        Node node3 = new Node("smith", null);
        node2.next = node3;//将node2结点挂载到node3

        Node node4 = new Node("lucy", null);
        table[3] = node4;//把node4放到table表索引为3的位置
        System.out.println(table);
    }
}
class Node{//创建结点
    Object item;//存放数据
    Node next;//指向下一结点

    public Node(Object item, Node next) {
        this.item = item;
        this.next = next;
    }
}
import java.util.HashSet;

/*
    HashSet源码解读
      1.添加一个元素时,先得到hash值,会转成索引值
    2.找到存储数据表table,看这个索引位置是否已存入元素
      如果没有则直接加入
      如果有,调用equals比较,如果相同,则放弃添加,如果不相同,则添加到最后(.next)
    3.第一次添加时,table数组扩容到16,临界值是16*加载因子(0.75)=12
      如果table数组到了临界值12,就会扩容到16*2=32,新的临界值为32*0.75=24,以此类推..
    4.在Java8中,如果一条链表的元素个数到达TREEIFY_THRESHOLD(默认为8),且table大小>=MIN_TREEIFY_CAPACITY(默认64)
      就会进行树化(红黑树),否则仍然采用数组扩容机制
 */
@SuppressWarnings({"all"})
public class Set04 {
    public static void main(String[] args) {
        HashSet hashSet = new HashSet();
        hashSet.add("java");//
        hashSet.add("hello");
        hashSet.add("java");
        System.out.println("set=" + hashSet);
    }
}
/*
        1.执行 HashSet()
        public HashSet() {
        map = new HashMap<>();
        }

        2. 执行 add()
        public boolean add(E e) {//e = "java"
        return map.put(e, PRESENT)==null;   //(static) PRESENT = new Object();
         }

        3.执行 put(),该方法会执行 hash(key) 得到 key 对应的 hash 值 算法 h = key.hashCode()) ^ (h >>> 16)
         public V put(K key, V value) {//key = "java", value = PRESENT 共享
         return putVal(hash(key), key, value, false, true); }

        4.执行 putVal
        final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;//定义了辅助变量
        //table就是HashMap的一个数组,类型是Node[]
        //if语句表示当前table为Null或大小为0,则第一次扩容,16个空间
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        //根据key得到hash,计算该key应存放到table表的哪个索引位置,并把这个位置的对象赋给p
        //判断p是否为空,如果为空,则创建一个Node(key="java",value=PRESENT)
        //放在该位置tab[i] = newNode(hash, key, value, null);
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;//定义辅助变量
            //如果当前索引位置对应的链表的第一个元素和准备添加的key和hash一样
            //且满足准备加入的key和p指向Node结点的key是同一个对象
            //或p指向Node结点的key的equals()和准备的加入key相同
            //就不能加入
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            //判断p是不是一颗红黑树,如果是,则调用putTreeVal来添加
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);

            //如果table对应索引位置,已经为一个链表,就使用for循环比较
            //依次和每一个元素比较,如果都不相同,则加入链表的最后
            //立即判断该链表是否已达到8个结点,调用treeifyBin,对当前这个链表进行树化
            //树化时进行判断
            //if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY(64))
            //                  resize();
            //如果上面条件成立,先 table 扩容
            //只有上面条件不成立时,才进行转成红黑树
            //如果有相同的,直接break
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;//修改次数
        //size 就是我们每加入一个结点 Node(k,v,h,next), size++
        if (++size > threshold)
            resize();//扩容
        afterNodeInsertion(evict);
        return null;
    }

 */
import java.util.HashSet;
import java.util.Objects;
/*
    HashSet练习1
    定义一个Employee类,包含private成员属性name,age
    要求创建三个Employee对象放入HashSet中
    当name和age值相同时,认为是同一个员工,不能添加到HashSet集合中
 */
@SuppressWarnings({"all"})
public class Set05 {
    public static void main(String[] args) {
        HashSet hashSet = new HashSet();
        hashSet.add(new Employee("jack",18));
        hashSet.add(new Employee("john",18));
        hashSet.add(new Employee("jack",18));
        System.out.println(hashSet);

    }
}
class Employee{
    private String name;
    private int age;
    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    //因为hash值不同,所以有三个对象--->重写hashCode
    //重写equals和hashCode
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return age == employee.age &&
                Objects.equals(name, employee.name);
    }
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}
import java.util.LinkedHashSet;
import java.util.Set;
/*
    LinkedHashSet
    1.LinkedHashSet是HashSet的子类
    2.LinkedHashSet底层是一个LinkedHashMap,底层维护了一个 数组+双向链表(pre,next)
    3.LinkedHashSet根据元素的hashCode值来决定元素的存储位置,同时使用链表维护元素的次序
      使元素看起来是以插入顺序来保存的
    4.LinkedHashSet不允许添加重复元素
 */
@SuppressWarnings({"all"})
public class Set06 {
    public static void main(String[] args) {
        Set set = new LinkedHashSet();
        set.add(123);
        set.add(456);
        set.add(123);
        set.add("jack");
        set.add(789);
        System.out.println(set);//[123, 456, jack, 789]
        //加入顺序和取出元素顺序一致
    }
}

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nzmzmc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值