有hashset,linkedhashset,treeset三种
hashset
怎么做到:
底层就是hashmap
每加入一个元素,会调用该元素的equals和hashcode算法,和已有的元素进行比较,若是不同就加入,若是相同则不加入(首先是比较hashcode的值,然后是equals的方法)
.将自定义类的对象存入HashSet去重复
* 类中必须重写hashCode()和equals()方法,自定义的类没有判断就不会有去重的功能
* hashCode(): 属性相同的对象返回值必须相同, 属性不同的返回值尽量不同(减少equals的判断,从而提高效率).通常想查找一个集合中是否包含某个对象,就是逐一取出每个元素与要查找的元素进行比较,当发现某个元素与要查找的对象进行equals方法比较的结果相等时,则停止继续查找并返回肯定的信息,否则返回否定的信息,如果一个集合中有很多元素譬如成千上万的元素,并且没有包含要查找的对象时,则意味着你的程序需要从该集合中取出成千上万个元素进行逐一比较才能得到结论,于是,有人就发明了一种哈希算法来提高从集合中查找元素的效率,这种方式将集合分成若干个存储区域,每个对象可以计算出一个哈希码,可以将哈希码分组,每组分别对应某个存储区域,根据一个对象的哈希码就可以确定该对象应该存储的那个区域。
* equals(): 属性相同返回true, 属性不同返回false,返回false的时候存储
linkedhashset:
原理和hashset是一样的,只是通过双向链表进行存储,是保证怎么存就怎么取的
-
LinkedHashSet.Node
或LinkedHashSet.Entry
的实例)
/**
* LinkedHashMap entry.
*/
private static class Entry<K,V> extends HashMap.Entry<K,V> {
// These fields comprise the doubly linked list used for iteration.
Entry<K,V> before, after;
Entry(int hash, K key, V value, HashMap.Entry<K,V> next) {
super(hash, key, value, next);
}
- 创建新节点时
Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
LinkedHashMap.Entry<K,V> p =
new LinkedHashMap.Entry<K,V>(hash, key, value, e);
linkNodeLast(p);
return p;
}
LinkedHashSet
:它继承与HashSet、又基于LinkedHashMap来实现的。
LinkedHashSet底层使用LinkedHashMap来保存所有元素,它继承与HashSet,其所有的方法操作上又与HashSet相同,因此LinkedHashSet 的实现上非常简单,使用双向链表来维护元素的插入顺序。因此,当遍历
LinkedHashSet
时,你会看到元素是按照它们被插入的顺序(FIFO,先进先出)来排列的。虽然这会增加一些额外的空间开销(用于维护链表),但遍历性能通常仍然很好,因为链表遍历是线性的。
treeset:
元素唯一,并且有序
怎么做的:
.自然顺序(Comparable,通过对象元素实现其接口)
* TreeSet类的add()方法中会把存入的对象提升为Comparable类型
* 调用对象的compareTo()方法和集合中的对象比较
* 根据compareTo()方法返回的结果进行存储
* b.比较器顺序(Comparator)
* 创建TreeSet的时候可以制定 一个Comparator
* 如果传入了Comparator的子类对象, 那么TreeSet就会按照比较器中的顺序排序
* add()方法内部会自动调用Comparator接口中compare()方法排序
* 调用的新传入的对象是compare()方法的第一个参数,集合中的对象是compare方法的第二个参数
* c.两种方式的区别
* TreeSet构造函数什么都不传, 默认按照类中Comparable的顺序(没有就报错ClassCastException)
* TreeSet如果传入Comparator, 就优先按照Comparator
就这样形成一个二叉树,小的在左边,大的再右边,一般相等的话就不存
若是改变两个从compare方法的返回值,如全都改为返回1,就能够保证怎么存就怎么取,改为-1的话,就会逆序存储,返回0的话就只有一个元素了
相比list的而言,set的遍历只能通过迭代器的方式
它的删除直接调用remove的方法即可,因为数据唯一,不需要进行遍历判断
它的修改只能先删除对应的元素,修改完后重新添加上去