HashSet

(底层是HashMap)

Set不允许元素重复。

基于HashMap实现,无容量限制。

是非线程安全的。

成员变量

private transient HashMap<E,Object> map;

// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();

构造方法

/*** Constructs a new, empty set; the backing <tt>HashMap</tt> instance has* default initial capacity (16) and load factor (0.75).*/
public HashSet() {map = new HashMap<>();
}
public HashSet(int initialCapacity) {map = new HashMap<>(initialCapacity);
}
public HashSet(int initialCapacity, float loadFactor) {map = new HashMap<>(initialCapacity, loadFactor);
}

添加

public boolean add(E e) {return map.put(e, PRESENT)==null;
}

删除

public boolean remove(Object o) {return map.remove(o)==PRESENT;
}

遍历

public Iterator<E> iterator() {return map.keySet().iterator();
}

包含

public boolean contains(Object o) {return map.containsKey(o);
}

TreeSet

(底层是TreeMap)

基于TreeMap实现,支持排序(自然排序 或者 根据创建TreeSet 时提供的 Comparator 进行排序)。

是非线程安全的。

成员变量

/**
 * The backing map.
 */

private transient NavigableMap<E,Object> m;

// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();

构造方法

public TreeSet() {this(new TreeMap<E,Object>());
}public TreeSet(Comparator<? super E> comparator) {this(new TreeMap<>(comparator));
}

添加

public boolean add(E e) {return m.put(e, PRESENT)==null;
}

删除

public boolean remove(Object o) {return m.remove(o)==PRESENT;
}

遍历

public Iterator<E> iterator() {return m.navigableKeySet().iterator();
}

包含

public boolean contains(Object o) {return m.containsKey(o);
}

获取开头

public E first() {return m.firstKey();
}

获取结尾

public E last() {return m.lastKey();
}

子集

public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,E toElement,   boolean toInclusive) {return new TreeSet<>(m.subMap(fromElement, fromInclusive,toElement,   toInclusive));
}

默认是含头不含尾

public SortedSet<E> subSet(E fromElement, E toElement) {return subSet(fromElement, true, toElement, false);
}

LinkedHashSet

(继承自HashSet,底层是LinkedHashMap)

LinkedHashSet继承自HashSet,源码更少、更简单,唯一的区别是LinkedHashSet内部使用的是LinkHashMap。这样做的意义或者好处就是LinkedHashSet中的元素顺序是可以保证的,也就是说遍历序和插入序是一致的

类声明

public class LinkedHashSet<E>
    extends HashSet<E>
    implements Set<E>, Cloneable, java.io.Serializable {}

构造方法

public LinkedHashSet(int initialCapacity, float loadFactor) {super(initialCapacity, loadFactor, true);
}/*** Constructs a new, empty linked hash set with the specified initial* capacity and the default load factor (0.75).** @param   initialCapacity   the initial capacity of the LinkedHashSet* @throws  IllegalArgumentException if the initial capacity is less*              than zero*/
public LinkedHashSet(int initialCapacity) {super(initialCapacity, .75f, true);
}/*** Constructs a new, empty linked hash set with the default initial* capacity (16) and load factor (0.75).*/
public LinkedHashSet() {super(16, .75f, true);
}

super指的是HashSet的default访问级别的构造方法

/*** Constructs a new, empty linked hash set.  (This package private* constructor is only used by LinkedHashSet.) The backing* HashMap instance is a LinkedHashMap with the specified initial* capacity and the specified load factor.** @param      initialCapacity   the initial capacity of the hash map* @param      loadFactor        the load factor of the hash map* @param      dummy             ignored (distinguishes this*             constructor from other int, float constructor.)* @throws     IllegalArgumentException if the initial capacity is less*             than zero, or if the load factor is nonpositive*/
HashSet(int initialCapacity, float loadFactor, boolean dummy) {map = new LinkedHashMap<>(initialCapacity, loadFactor);
}

BitSet

(位集,底层是long数组,用于替代List<Boolean>)

BitSet是位操作的对象,值只有0或1即false和true,内部维护了一个long数组,初始只有一个long,所以BitSet最小的size是64(8个字节64个位,可以存储64个数字),当随着存储的元素越来越多,BitSet内部会动态扩充,最终内部是由N个long来存储,这些针对操作都是透明的。

默认情况下,BitSet的所有位都是false即0。

不是线程安全的。

用1位来表示一个数据是否出现过,0为没有出现过,1表示出现过。使用的时候既可根据某一个是否为0表示,此数是否出现过。

一个1GB的空间,有8*1024*1024*1024 = 8.58*10^9bit,也就是1GB的空间可以表示85亿多个数。

常见的应用是那些需要对海量数据进行一些统计工作的时候,比如日志分析、用户数统计等等,如统计40亿个数据中没有出现的数据,将40亿个不同数据进行排序,海量数据去重等等。

JDK选择long数组作为BitSet的内部存储结构是出于性能的考虑,因为BitSet提供and和or这种操作,需要对两个BitSet中的所有bit位做and或者or,实现的时候需要遍历所有的数组元素。使用long能够使得循环的次数降到最低,所以Java选择使用long数组作为BitSet的内部存储结构。

去重示例

public static void containChars(String str) {BitSet used = new BitSet();for (int i = 0; i < str.length(); i++)used.set(str.charAt(i)); // set bit for char StringBuilder sb = new StringBuilder();sb.append("[");int size = used.size();for (int i = 0; i < size; i++) {if (used.get(i)) {sb.append((char) i);}}sb.append("]");System.out.println(sb.toString());
}public static void main(String[] args) {containChars("abcdfab");
}

[abcdf]

排序示例

public static void sortArray(int[] array) {BitSet bitSet = new BitSet(2 << 13);// 虽然可以自动扩容,但尽量在构造时指定估算大小,默认为64 System.out.println("BitSet size: " + bitSet.size());for (int i = 0; i < array.length; i++) {bitSet.set(array[i]);}//剔除重复数字后的元素个数 int bitLen = bitSet.cardinality();//进行排序,即把bit为true的元素复制到另一个数组 int[] orderedArray = new int[bitLen];int k = 0;for (int i = bitSet.nextSetBit(0); i >= 0; i = bitSet.nextSetBit(i + 1)) {orderedArray[k++] = i;}System.out.println("After ordering: ");for (int i = 0; i < bitLen; i++) {System.out.print(orderedArray[i] + "\t");}
}public static void main(String[] args) {int[] array = new int[]{423, 700, 9999, 2323, 356, 6400, 1, 2, 3, 2, 2, 2, 2};sortArray(array);
}

BitSet size: 16384

After ordering:

1     2     3     356 423 700 2323      6400      9999

CopyOnWriteArraySet

(底层是CopyOnWriteArrayList)

基于CopyOnWriteArrayList实现,其唯一的不同是在add时调用的是CopyOnWriteArrayList的addIfAbsent方法。

在每次add的时候都要进行数组的遍历,因此其性能会略低于CopyOnWriteArrayList。

终于,我读懂了所有Java集合——set篇相关推荐

  1. 终于,我读懂了所有Java集合——map篇

    首先,红黑树细节暂时撸不出来,所以没写,承诺年前一定写 HashMap (底层是数组+链表/红黑树,无序键值对集合,非线程安全) 基于哈希表实现,链地址法. loadFactor默认为0.75,thr ...

  2. 终于,我读懂了所有Java集合——map篇(多线程)

    多线程环境下的问题 1.8中hashmap的确不会因为多线程put导致死循环(1.7代码中会这样子),但是依然有其他的弊端,比如数据丢失等等.因此多线程情况下还是建议使用ConcurrentHashM ...

  3. 终于,我读懂了所有Java集合——List篇

    ArrayList 基于数组实现,无容量的限制. 在执行插入元素时可能要扩容,在删除元素时并不会减小数组的容量,在查找元素时要遍历数组,对于非null的元素采取equals的方式寻找. 是非线程安全的 ...

  4. 终于,我读懂了所有Java集合——queue篇

    Stack 基于Vector实现,支持LIFO. 类声明 public class Stack<E> extends Vector<E> {} push public E pu ...

  5. 终于,我读懂了所有Java集合——sort

    Collections.sort 事实上Collections.sort方法底层就是调用的Arrays.sort方法,而Arrays.sort使用了两种排序方法,快速排序和优化的归并排序. 快速排序主 ...

  6. 图解易经:一部终于可以读懂的易经 祖行 扫描版 陕西师范大学出版社

    图解易经:一部终于可以读懂的易经  祖行  扫描版  陕西师范大学出版社

  7. 《图解易经:一本终于可以读懂的易…

    <图解易经:一本终于可以读懂的易经>(祖行)扫描版[PDF] 中文名: 图解易经:一本终于可以读懂的易经 作者: 祖行 图书分类: 教育/科技 资源格式: PDF 版本: 扫描版 出版社: ...

  8. Java 集合容器篇面试题(上)-王者笔记《收藏版》

    前期推荐阅读: Java基础知识学习总结(上) Java 基础知识学习总结(下) 大学生一个暑假学会5个神仙赚钱技能 | 你学会了几个? 毕设/私活/大佬必备,一个挣钱的开源前后端分离脚手架 目录 一 ...

  9. 网络编程懒人入门(十二):快速读懂Http/3协议,一篇就够!

    本文中文译文由作者"ably.io"发布于公众号"高可用架构",译文原题:<深入解读HTTP3的原理及应用>.英文原题:<HTTP/3 dee ...

最新文章

  1. 物体抓取位姿估計算法綜述_大盘点|6D姿态估计算法汇总(上)
  2. 华为手环怎么没有上鸿蒙,不再是大号手环!华为鸿蒙手表来了:要和苹果抢生态?...
  3. 重磅!阿里发布全新操作系统,这次要干翻 CentOS 了!
  4. js String方法集合
  5. 瑞柏匡丞_移动互联的发展现状与未来
  6. ebp 函数堆栈esp_函数堆栈调用过程
  7. html设置窗口最小大小,调整HTML 5画布的大小以适应窗口
  8. 使用LD链接时候文件的顺序
  9. python随机数据库_Python实现生成随机数据插入mysql数据库的方法
  10. 学计算机语言需要英语基础吗,数学和英语不好的人能学编程吗?
  11. IOS在Windows自动化测试之tidevice
  12. 初学者如何学好编程?
  13. impala 基础知识及使用
  14. 第四届传智杯(初赛B组) | python题解思路
  15. C - 开门人和关门人(结构体+sort)
  16. 3.1.2 宽带路由器方案
  17. python3.7安装scrapy_Python3.7下scrapy框架的安装
  18. flask:SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default i
  19. livereload使用方法
  20. 个人开发android如何赚钱

热门文章

  1. 三角形和矩形傅里叶变换_信号与系统:第三章傅立叶变换2.ppt
  2. oracle自动撤销管理,Oracle 9i中自动撤销管理的优点分析
  3. 如何构建自己的SIP SERVER!
  4. mysql client 未开启_Django+mysqlclient未关闭数据库连接
  5. php获取网页输出,PHP 利用AJAX获取网页并输出的实现代码(Zjmainstay)_PHP教程
  6. 【转】30分钟学会UML类图
  7. 【转】理解OAuth 2.0
  8. SharePoint2010开发最佳实践
  9. 一步步编写操作系统21 x86虚拟机bochs 跟踪bios
  10. java 切换panel会闪烁_【19期】为什么Java线程没有Running状态?