HashSet 学习


package cn.onloc.utils.conllection;

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

public class HashSet_1 {

    /** 1、为什么要用Set
     *    其实在对set的了解之前最好先去熟悉Map的,最好对hash结构有一定的基础。
     *    其实在有了数组和链表以后,对一个单个数据类型的存储已经有了两种方式,之所以需要set是因为前两个集合对数据的存储都是顺序的,顺序的意思就是不管你给我什么,我都按照你给的顺序
     *    给你存储下去,即使你给我两个一样的数据,那我就给你存储两份,这就造成了在一些情况下,这样是不能满足要求的,所以需要set这种无需且不重复的集合类型。
     *    a、都知道熟悉的数据结构大体分三类:
     *          数组(内存中的一款块连续空间)
     *          链表(内存中的位置不定,但是通过每个对象中包含的首位地址值能关联找到具体指,也是不用循环整个内存地址去查询的)
     *          树结构(树结构的出现,首先是用来解决很多的排序比较问题,后来扩散越来越多种类,具体后面记录)
     *    对了collection的分类也是主要分为三类:
     *          list: 然后list根据底层结构的不同分为两种:(ArrayList、LinkedLsit)
     *          Set:根据底层的不同分为(HashSet、TreeSet)
     *          Queue: 队列,只要对数据结构定义好方法,实现先进先出的原则即为队列
     *
     *    继承体系:
     *    HashSet  extends AbstractSet implements set -- 再次实现set是为了在进行接口代理的时候,能生成相关的代理类
     *    AbstractSet extends AbstractCollection implements set -- 接口抽象类的定义模式
     *
     *    HashMap的底层是map的key,具体理解后面补充。见HashMap的总结
     *
     *    现在先说HashSet: 无序、不重复
     *    HAshSet的底层根据HashMap一样,是一个数组加上链表的格式,因为这是一个Hash的一种实现结构。所有在创建一个HashSet的时候,实际是要先去内存创建一个固定容量的数组,根据
     *    HashMap的基本定义,这个初始化的数组容量为16,默认的hashMap的加载因子为0.75,也就是当这个数组的容量达到最大值的0.75时,会对数组进行扩容,扩大为原来的两倍。所以在调用
     *    HashSet的add方法的时候,程序首先根据你传入的要添加的值去算出他的HashCode值来,然后在根据这个HashCode和当前数组的容量一起当做入参传入一个Hash函数,算去该值存在数组中的
     *    具体位置,所以他是无序的。同样的,当一个相同的值存储进来是,会因为他的HashCode和数组的容量不变而去存储在上一个相同值的位置上,也就做到了不重复的结构。还有一种情况就是当
     *    一个值算出来他的hashCode值是相等的,但是他存储的值不一样的时候,其实在执行HashMap的put方法时,在计算好该值在数组中的存储位置以后,会把该位置上原始的OLdValue值拿出来与
     *    新存入的值进行对比,
     *       if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
     *      如上,会用到equals方法进行具体指的对比。
     *
     *
     *    自己觉得一个集合的操作需要哪些:
     *    1、新增
     *          public boolean add(E e), 像一个HashSet容器中添加一个元素e。因为set不能重复,在set的add方法里会把HashMap的put方法的结果拿来比较,
     *          因为HashMap的put方法会把计算出数组位置的值返回回去,如果这个位置没有相关联的数据,则返回一个null,
     *          可以理解为数组的初始化值,set就判断这个值是否是null来进行判断.如果为null则表示该位置以前是没有值的,返回true。反之
     *    2、删除
     *          public boolean remove(E e) , 首先hashSet因为是无序的肯定不能根据下标来进行删除只能根据值来删除。调用的也是HashMap的remove(), 首先根据传入的值去算出其在数组中的
     *          下标,当下标不存在时,返回一个null和HashSet的Object地址对比不同,则返回一个False,否则返回true,因为HashSet的这个下层Hash结构中,没个存值的节点保存的是同一个Object的地址值
     *    3、查询(取值)
     *          Iterator iterator = set.iterator();
     *          其实仔细理解,HashSet底层存储的数组大小固定,但是其具体存储的位置是不确定的,所以对他的取值,只能通过遍历实现;当然我会想collection集合框架不是都有结果的size()吗,那我
     *          使用for循环能否实现查找呢? 其实for循环能实现的查找都是对有序的集合,无序的就没办法对数组进行遍历了,而且对于HashSet的size(),只是记录了底层数组中的值有多少,这些值
     *          是无序存储在数组中的,所以不能通过遍历查询到,除非知道Hashset中整个数组的length和数组对象,但是HashSet的内部结构肯定是透明的,所以不能通过for。
     *
     *          在写一下对于iterator的理解:
     *          iterator是一个迭代器接口,他是根据collection提供的一个接口方法来返回一个Iterator接口的,他的具体实现是在每个集合的内部,就以HashMap为例:
     *          hashMap类中有一个叫做HashIterator的内部类,该类中实现了对迭代器的常用功能,
     *          public boolean hashNext(),  都知道HashMap的内部结构是数组加上链表,而且数组中存储了元素的位置是随机且不连续的。
     *              HashMap源码:
     *              if (t != null && size > 0) { // advance to first entry
     *                 do {} while (index < t.length && (next = t[index++]) == null);
     *             }
     *           在HashMap的抽象内部类中,定义个两个变量,一个用来当前节点对象,一个叫做next,用来记录当前一个不为空的节点对象。(这很重要),当使用迭代器的hasNext()的时候,
     *           就直接判断next对象是否为空就能知道该iterator是否还能继续遍历。
     *          public E next();
     *          在对HashMap的key使用iterator的时候,主要用到的是HashIterator的nextNode().它会去获取到数组下的对应链表结构部位null的那个节点,然后把取出来的值返回给next()f方法。
     *          public void remove(); 整个remove的方法就是一个数组或者链表的删除节点问题。
     *
     *    4、修改
     *          仔细想想,对于一个不知道存放在数组具体位置的值是不能修改他的值的。但是有一点要注意,如果是引用类型,他存放的只是一个地址,具体的指向是可以修改的
     *
     *    5、循环
     *          用iterator
     *    6、排序
     *          所谓无序,还怎么排序
     *    7、包含
     *          Contanins()
     *    8、复制
     *          HashSet实现了Clone接口,具体的对象Clone牵扯到浅Clone和深Clone,在后面单独说
     *    9、对toArray的实现
     *
     *
     *
     */
    public static void main(String[] args) {

        {
            //新增
            Set<Integer> set = new HashSet();
            boolean a = set.add(1);
            boolean b = set.add(2);
            boolean c = set.add(3);
            boolean d = set.add(1);
            System.out.println("hashSet---add : " + set + ", a = " + a + ", b = " + b + ", c = " + c + ", d = " + d);
            //hashSet---add : [1, 2, 3], a = true, b = true, c = true, d = false
            System.out.println("hashSet---size() : " + set.size());
            //hashSet---size() : 3
        }

        {
            //删除
            Set<Integer> set = new HashSet();
            boolean a = set.add(1);
            boolean b = set.add(2);
            boolean c = set.add(3);
            boolean d = set.add(4);
            System.out.println("HashSet 原始值 : " + set);//HashSet 原始值 : [1, 2, 3, 4]
            boolean ra = set.remove(2);
            System.out.println("HashSet 删除后 : " + set + " ,删除结果: " + ra);
            //HashSet 删除后 : [1, 3, 4] ,删除结果: true
            boolean rb = set.remove(6);
            System.out.println("HashSet 删除后 : " + set + " ,删除结果: " + rb);
            //HashSet 删除后 : [1, 3, 4] ,删除结果: false
        }

        {
            //查询
            Set<Integer> set = new HashSet();
            boolean a = set.add(1);
            boolean b = set.add(2);
            boolean c = set.add(3);
            boolean d = set.add(null);
            System.out.println("HashSet 原始值 : " + set);// HashSet 原始值 : [null, 1, 2, 3]

            Iterator<Integer> iterator = set.iterator();
            while(iterator.hasNext()) {
                System.out.println("  iterator : " + iterator.next());
            }
            //  iterator : null
            //  iterator : 1
            //  iterator : 2
            //  iterator : 3
        }

        {
            //toArray
            Set<Integer> set = new HashSet();
            boolean a = set.add(1);
            boolean b = set.add(2);
            boolean c = set.add(34);
            boolean d = set.add(null);
            System.out.println("HashSet 原始值 : " + set);// HashSet 原始值 : [null, 1, 2, 3]

            Object[] arr = set.toArray();
            System.out.println("arr : " + arr);
            //arr : [Ljava.lang.Object;@404b9385
            for(Object i : arr) {
                System.out.println("  toArray : " + i);
            }
            //  toArray : null
            //  toArray : 1
            //  toArray : 2
            //  toArray : 34

        }

    }

}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值