JAVA 基础 :Set——你真的了解吗?

简述

Set 继承于 Collection ,是一种集合。有元素无序、值不重复、不允许空值得特性。主要有HashSet、TreeSet两种实现方式。由于Set主要基于Map实现,所以特点也由Map决定。

Set 结构图

例如 HashSet ,调用 HashSet 的无参构造函数,HashSet 会使用默认的 HashMap ,初始化 Size 为16,扩张系数为0.75

HashSet

官方文档

官方文档翻译

构造方法官方文档

构造方法官方文档翻译

HashSet 结构图

查看 HashSet 源码会发现主要数据操作都间接调用 HashMap 的数据操作,从 add() 方法可以看出 HashSet 的值其实为 HashMap 的 Key,而 Value 是一个关键字为 final 类型为 Object 的 PRESENT ,遍历的 HashSet 的值其实是遍历 HashMap 的 KeyEntry .

HashSet 源码

public class HashSet

extends AbstractSet

implements Set, Cloneable, java.io.Serializable

{

static final long serialVersionUID = -5024744406713321676L;

private transient HashMap 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 HashMap instance has

* default initial capacity (16) and load factor (0.75).

*/

public HashSet() {

map = new HashMap<>();

}

/**

* Constructs a new set containing the elements in the specified

* collection. The HashMap is created with default load factor

* (0.75) and an initial capacity sufficient to contain the elements in

* the specified collection.

*

* @param c the collection whose elements are to be placed into this set

* @throws NullPointerException if the specified collection is null

*/

public HashSet(Collection extends E> c) {

map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));

addAll(c);

}

/**

* Constructs a new, empty set; the backing HashMap instance has

* 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

* @throws IllegalArgumentException if the initial capacity is less

* than zero, or if the load factor is nonpositive

*/

public HashSet(int initialCapacity, float loadFactor) {

map = new HashMap<>(initialCapacity, loadFactor);

}

/**

* Constructs a new, empty set; the backing HashMap instance has

* the specified initial capacity and default load factor (0.75).

*

* @param initialCapacity the initial capacity of the hash table

* @throws IllegalArgumentException if the initial capacity is less

* than zero

*/

public HashSet(int initialCapacity) {

map = new HashMap<>(initialCapacity);

}

/**

* 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);

}

/**

* Returns an iterator over the elements in this set. The elements

* are returned in no particular order.

*

* @return an Iterator over the elements in this set

* @see ConcurrentModificationException

*/

public Iterator iterator() {

return map.keySet().iterator();

}

/**

* Returns the number of elements in this set (its cardinality).

*

* @return the number of elements in this set (its cardinality)

*/

public int size() {

return map.size();

}

/**

* Returns true if this set contains no elements.

*

* @return true if this set contains no elements

*/

public boolean isEmpty() {

return map.isEmpty();

}

/**

* Returns true if this set contains the specified element.

* More formally, returns true if and only if this set

* contains an element e such that

* (o==null ? e==null : o.equals(e)).

*

* @param o element whose presence in this set is to be tested

* @return true if this set contains the specified element

*/

public boolean contains(Object o) {

return map.containsKey(o);

}

/**

* Adds the specified element to this set if it is not already present.

* More formally, adds the specified element e to this set if

* this set contains no element e2 such that

* (e==null ? e2==null : e.equals(e2)).

* If this set already contains the element, the call leaves the set

* unchanged and returns false.

*

* @param e element to be added to this set

* @return true if this set did not already contain the specified

* element

*/

public boolean add(E e) {

return map.put(e, PRESENT)==null;

}

/**

* Removes the specified element from this set if it is present.

* More formally, removes an element e such that

* (o==null ? e==null : o.equals(e)),

* if this set contains such an element. Returns true if

* this set contained the element (or equivalently, if this set

* changed as a result of the call). (This set will not contain the

* element once the call returns.)

*

* @param o object to be removed from this set, if present

* @return true if the set contained the specified element

*/

public boolean remove(Object o) {

return map.remove(o)==PRESENT;

}

/**

* Removes all of the elements from this set.

* The set will be empty after this call returns.

*/

public void clear() {

map.clear();

}

/**

* Returns a shallow copy of this HashSet instance: the elements

* themselves are not cloned.

*

* @return a shallow copy of this set

*/

@SuppressWarnings("unchecked")

public Object clone() {

try {

HashSet newSet = (HashSet) super.clone();

newSet.map = (HashMap) map.clone();

return newSet;

} catch (CloneNotSupportedException e) {

throw new InternalError(e);

}

}

/**

* Save the state of this HashSet instance to a stream (that is,

* serialize it).

*

* @serialData The capacity of the backing HashMap instance

* (int), and its load factor (float) are emitted, followed by

* the size of the set (the number of elements it contains)

* (int), followed by all of its elements (each an Object) in

* no particular order.

*/

private void writeObject(java.io.ObjectOutputStream s)

throws java.io.IOException {

// Write out any hidden serialization magic

s.defaultWriteObject();

// Write out HashMap capacity and load factor

s.writeInt(map.capacity());

s.writeFloat(map.loadFactor());

// Write out size

s.writeInt(map.size());

// Write out all elements in the proper order.

for (E e : map.keySet())

s.writeObject(e);

}

/**

* Reconstitute the HashSet instance from a stream (that is,

* deserialize it).

*/

private void readObject(java.io.ObjectInputStream s)

throws java.io.IOException, ClassNotFoundException {

// Read in any hidden serialization magic

s.defaultReadObject();

// Read capacity and verify non-negative.

int capacity = s.readInt();

if (capacity < 0) {

throw new InvalidObjectException("Illegal capacity: " +

capacity);

}

// Read load factor and verify positive and non NaN.

float loadFactor = s.readFloat();

if (loadFactor <= 0 || Float.isNaN(loadFactor)) {

throw new InvalidObjectException("Illegal load factor: " +

loadFactor);

}

// Read size and verify non-negative.

int size = s.readInt();

if (size < 0) {

throw new InvalidObjectException("Illegal size: " +

size);

}

// Set the capacity according to the size and load factor ensuring that

// the HashMap is at least 25% full but clamping to maximum capacity.

capacity = (int) Math.min(size * Math.min(1 / loadFactor, 4.0f),

HashMap.MAXIMUM_CAPACITY);

// Create backing HashMap

map = (((HashSet>)this) instanceof LinkedHashSet ?

new LinkedHashMap(capacity, loadFactor) :

new HashMap(capacity, loadFactor));

// Read in all elements in the proper order.

for (int i=0; i

@SuppressWarnings("unchecked")

E e = (E) s.readObject();

map.put(e, PRESENT);

}

}

/**

* Creates a late-binding

* and fail-fast {@link Spliterator} over the elements in this

* set.

*

*

The {@code Spliterator} reports {@link Spliterator#SIZED} and

* {@link Spliterator#DISTINCT}. Overriding implementations should document

* the reporting of additional characteristic values.

*

* @return a {@code Spliterator} over the elements in this set

* @since 1.8

*/

public Spliterator spliterator() {

return new HashMap.KeySpliterator(map, 0, -1, 0, 0);

}

}

TreeSet

TreeSet 和 HashSet 实现类似,间接调用内部的 TreeMap ,都是利用红黑树算法实现;TreeSet 会根据其元素的自然顺序对元素进行排序,元素依然是唯一的不可重复,元素不可为 null .

TreeSet 结构图

LinkedHashSet

介于 HashSet 与 TreeSet 之间,在 HashSet 的基础上增加了一个记录插入顺序的双链表。线程不安全有序不重复集合,基于 LinkedHashMap 实现,是 HashMap 与双向链表结合实现的,利用双向链表记录插入顺序,以保证迭代输出的有序性。

LinkedHashSet 结构图

ConcurrentSkipListSet

线程安全的有序不重复集合,适用于高并发场景;与 TreeSet 对比,相同点是都是有序集合,不同点有两方面,第一 TreeSet 是非线程安全的,第二 ConcurrentSkipListSet 是基于 ConcurrentSkipListMap 通过跳表数据结构实现而 TreeSet 是基于 TreeMap 通过红黑树算法实现。

ConcurrentSkipListSet 结构图

CopyOnWriteArraySet

线程安全的无序不重复集合,适用于高并发场景;与 HashSet 对比,相同点是都是无序集合,不同点有有两个,第一 HashSet 是非线程安全的,第二 CopyOnWriteArraySet 是基于 CopyOnWriteArrayList 通过动态数组数据结构实现而 HashSet 是基于 HashMap 通过散列表数据结构实现。

CopyOnWriteArraySet 结构图

EnumSet

Set针对枚举类型的接口实现类;通过位向量实现;EnumSet 中所有元素都必须是指定的枚举类型或枚举值,由 EnumSet 创建时指定,集合元素为有序、不重复、非 null ,元素的顺序与枚举类元素顺序相同;

EnumSet 结构图

JobStateReasons

JobStateReasons 结构图

ConcurrentHashMap.KeySetView

KeySetView 结构图

如有写的不对的地方请大家指正,万分感谢,相互学习,相互交流

java keysetview,Set——你真的了解吗?相关推荐

  1. Java最大的优势真的在于跨平台吗?

     Java最大的优势真的在于跨平台吗? 以下讨论只针对PC端和移动端. Java最大的优势真的在于跨平台吗?以前是,但现在已经不是了. 有跨平台需求的仅仅是客户端应用,而不是服务端.例如桌面应用, ...

  2. Java 中的 String 真的是不可变的吗

    转载自   Java 中的 String 真的是不可变的吗 我们都知道 Java 中的 String 类的设计是不可变的,来看下 String 类的源码. public final class Str ...

  3. [转载] Java内存管理-你真的理解Java中的数据类型吗(十)

    参考链接: Java中的字符串类String 1 做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! 推荐阅读 第一季 0.Java的线程安全.单例模式.JVM内存结构等知识 ...

  4. 曾经的 Java IDE 王者 Eclipse 真的没落了?21 款插件让它强大起来!

    俗话说,好马配好鞍,才能展现千里马的实力.一名好的开发者,必定要有一套好的开发工具才能打造出最好的产品给用户.要论世界上最好用的 IDE 是哪一种?有人会选择老牌的 Visual Studio 或是 ...

  5. 膜拜!阿里内部学习的五大深入理解Java虚拟机PDF,真的强

    前言 Java是目前用户最多.使用范围最广的软件开发技术,Java的技术体系主要由支撑Java程序运行的虚拟机.提供各开发领域接口支持的Java类库.Java编程语言及许许多多的第三方Java框架(如 ...

  6. java工程师的薪资真的有那么高吗?

    java工程师的薪资 以北京为例,对JAVA工程师岗位的平均工资.不同工作年限的收入水平进行分析对比,供大家在择业.就业的时候参考. 在上图中,北京Java工程师平均薪资为14830/月,取自6397 ...

  7. JAVA工程师的工资真的很高吗?

    Java工程师是个高薪的行业,让不少人羡慕不已,有很多人因为Java的高薪而转行.这也是近几年Java如此火热的原因之一.也正是因为Java如此之多,所以不少想要学习Java语言的人不禁产生一个疑问: ...

  8. c语言难还是java难_C语言真的比Java难学吗?

    原标题: C语言真的比Java难学吗? 千锋小编觉得C语言的设计目标是提供一种能以简易的方式编译.处理低级存储器.产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言.C语言语法比较简单便捷, ...

  9. 年年都有人说Java市场饱和,那Java行业到底是不是真的饱和了呢?

    所有人都知道Java程序员薪资高.加薪快.发展好.事实上的确如此. 这也导致了大量外行人涌入IT行业,于是慢慢又有了另一种说法:Java市场已经饱和,大家不要再学Java了,反正学完后找不到工作还得转 ...

最新文章

  1. Chapter 9:Noise-Estimation Algorithms
  2. Google Guice使用入门
  3. spring boot中使用Pagehelper实现分页
  4. struts2常用标签
  5. Visual Studio 2005 编译的版本无法启动,出现应用程序配置不正确的错误
  6. Alibaba Nacos 服务消费者工程接入nacos并实现调用服务提供者工程
  7. leetcode题解677-键值映射
  8. 详解float**类型和float*类型
  9. 如果出现网络请求3840的这种错误
  10. Linux服务器时间同步那些事
  11. hdu 3065 病毒侵袭持续中
  12. 一线实践 | 借助混沌工程工具 ChaosBlade 构建高可用的分布式系统
  13. 文件与base64的互相转换操作
  14. 无线通信设备安装工程概预算编制_电气设备安装工程计价与应用
  15. 计算机组成原理学习笔记-加法器
  16. 图像处理之常见二值化方法汇总
  17. linux 安装pureftp
  18. 用python将word转化成pdf
  19. Spring Boot项目出现 Invalid bound statement (not found):错误
  20. Oleg Shilo:基于CS-Script的Notepad++的插件_.Net技术

热门文章

  1. Android Caused by: java.lang.IllegalArgumentException: column '_id' does not exist
  2. 《看聊天记录都学不会Python到游戏实战?太菜了吧》(10)无底洞的循环
  3. 那些奇奇怪怪的男性用品......
  4. 你绝对干过的15件傻事儿
  5. 马斯克又要搞事情,不锈钢材质的Space X“星际飞船”正式亮相
  6. 丘成桐:完全不懂数学,才会有“数学无用”的说法
  7. HTML手机上图片显示被压扁,在重新调整Web浏览器HTML |时,文本会被压扁CSS
  8. arcgis oracle trace,ArcGIS应用Oracle Spatial特征分析
  9. 云服务器下行_腾讯云轻量应用服务器简单测评
  10. python3九九乘法表儿歌下载_python3的基础学习之九九乘法表和format函数,值得收藏...