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}
}
}
HashSet 学习
最新推荐文章于 2023-12-28 11:34:18 发布