Java:Set接口小记
Java:Set接口小记
对 Java 中的 Set接口 与 其实现类,做一个微不足道的小小小小记
概述
public interface Set<E> extends Collection<E> {
// ...
}
Set 接口继承了 Collection 接口,Set集合中不能包含重复的元素,每个元素必须是唯一的,你只要将元素加入 Set 中,重复的元素会自动移除。
对于 Set 的个人理解:
- 使用上:就是不能带有重复元素的 List;
- 本质上:只用了 key 的 Map,一个串了马甲的 Map
HashSet
概述
披着马甲的 HashMap:Java:HashMap类小记
public HashSet() {
map = new HashMap<>();
}
HashSet 中不能有相同的元素,但可以有 null 元素,即元素具有唯一性;
其底层采用的还是 HashMap,对于 put 元素,其采用的方式为:
// HashSet的底层为一个HashMao结构
private transient HashMap<E, Object> map;
// 作为一个占位符
// private static final Object PRESENT = new Object(); public HashSet() {
map = new HashMap<>();
}
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
从上述 add 方法可知:HashSet 保证元素不重复的方式
元素值作为的是 map 的 key,map 的 value 则是 PRESENT 变量,这个变量只作为放入 map 时的一个占位符而存在,所以没什么实际用处。其实,这时候答案已经出来了:HashMap 的 key 是不能重复的,而这里HashSet 的元素又是作为了 map 的 key,当然也不能重复了。
LinkedHashSet、TreeSet 都一样,都采用了 PRESENT 这个占位符。
存入 HashSet 的元素是无序的;
添加、删除元素的操作时间复杂度都为O(1);
非线程安全。
实现原理
HashSet 的实现是依赖于 HashMap 的,HashSet 的值都是存储在 HashMap 中的;
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable{}
在 HashSet 的构造法中会初始化一个 HashMap 对象,HashSet 的值是作为 HashMap 的 key 存储在 HashMap 中的,当存储的值已经存在时返回 false;
private transient HashMap<E,Object> map;
public HashSet() {
map = new HashMap<>();
}
public boolean add(E e) {
return map.put(e, PRESENT)==null;
// private static final Object PRESENT = new Object();
}
HashSet 的其他操作都是基于 HashMap 的
public int size() {
return map.size();
}
public boolean isEmpty() {
return map.isEmpty();
}
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
// ....
LinkedHashSet
概述
披着马甲的 LinkedHashMap:Java:LinkedHashMap类小记
public class LinkedHashSet<E>
extends HashSet<E>
implements Set<E>, Cloneable, java.io.Serializable { public LinkedHashSet(int initialCapacity, float loadFactor) {
// super:用了HashSet中的构造函数,且第三个参数为true
// 其他的构造函数也相同,第三个元素都为true
super(initialCapacity, loadFactor, true);
}
} // 进入HashSet查看对应的构造函数
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
// 这里new了一个LinkedHashMap
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
- LinkedHashSet 中不能有相同元素,可以有一个 null 元素,元素严格按照放入的顺序排列;
- 添加、删除元素的操作时间复杂度都为O(1);
- 非线程安全。
实现原理
对于 LinkedHashSet 而言,它继承于 HashSet、又基于 LinkedHashMap 来实现的;
public class LinkedHashSet<E>
extends HashSet<E> // 继承了hashset
implements Set<E>, Cloneable, java.io.Serializable { public LinkedHashSet(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor, true);
} public LinkedHashSet(int initialCapacity) {
super(initialCapacity, .75f, true);
} public LinkedHashSet() {
super(16, .75f, true);
}
}
LinkedHashSet 底层使用 LinkedHashMap 来保存所有元素,它继承于 HashSet,其所有的方法操作上又与 HashSet 相同;
TreeSet
概述
披着马甲的 TreeSet:Java:TreeMap类小记
public TreeSet() {
this(new TreeMap<E,Object>());
}
- TreeSet 是中不能有相同元素,不可以有null元素,根据元素的自然顺序进行排序;
- 添加、删除操作时间复杂度都是O(log(n));
- 非线程安全
实现原理
TreeSet 底层实际使用的存储容器就是 TreeMap;
public class TreeSet<E> extends AbstractSet<E>
implements NavigableSet<E>, Cloneable, java.io.Serializable
{
private transient NavigableMap<E,Object> m; public TreeSet() {
// 底层实际使用的存储容器就是 TreeMap;
this(new TreeMap<E,Object>()); // 调用 TreeSet
} // 把TreeMap赋值给了NavigableMap<E,Object>
TreeSet(NavigableMap<E,Object> m) {
this.m = m;
} public boolean add(E e) {
// 本质上还是调用了 TreeMap 的方法
return m.put(e, PRESENT)==null;
}
}
TreeSet 里绝大部分方法都是直接调用 TreeMap 的方法来实现的;
总结
首先,Set 集合不包含重复元素,都具有唯一性;
当无排序要求可以选用 HashSet;
若想取出元素的顺序和放入元素的顺序相同,那么可以选用 LinkedHashSet;
若想插入、删除立即排序或者按照一定规则排序可以选用 TreeSet。
参考
https://blog.csdn.net/StemQ/article/details/66477615
https://mp.weixin.qq.com/s/q1r9Pno6ANUzZ9wMzA-JSg
https://blog.csdn.net/qq_41026809/article/details/90449073
https://www.cnblogs.com/baojun/p/11087004.html
https://blog.csdn.net/jtcode_is_my_partner/article/details/81408392
Java:Set接口小记的更多相关文章
- Java:抽象类和接口小记
Java:抽象类和接口小记 对 Java 中的 抽象类和接口,做一个微不足道的小小小小记 抽象类:使用 abstract 修饰,子类用 extends 继承: 接口:使用 interface 修饰,采 ...
- Java:AQS 小记-2(ReentrantLock)
Java:AQS 小记-2(ReentrantLock) 整体结构 ReentrantLock 类图 AbstractOwnableSynchronizer 类 public abstract cla ...
- Java:ThreadLocal小记
Java:ThreadLocal小记 说明:这是看了 bilibili 上 黑马程序员 的课程 java基础教程由浅入深全面解析threadlocal 后做的笔记 内容 ThreadLocal 介绍 ...
- Java:内部类小记
Java:内部类小记 对 Java 中的 内部类,做一个微不足道的小小小小记 首先:内部类是指在一个外部类的内部再定义一个类.内部类作为外部类的一个成员,并且依附于外部类而存在的. 成员内部类 成员内 ...
- Java:异常小记
Java:异常小记 对 Java 中的 异常 ,做一个微不足道的小小小小记 Error 和 Exception 相同点: Exception 和Error 都是继承了 Throwable 类,在 Ja ...
- Java:创建对象小记
Java:创建对象小记 对 Java 中的创建对象的内容,做一个微不足道的小小小小记 创建对象的方式概述 使用 new 关键字:Person person = new Person(); 反射创建:使 ...
- 深入理解Java的接口和抽象类(转)
深入理解Java的接口和抽象类 对于面向对象编程来说,抽象是它的一大特征之一.在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类.这两者有太多相似的地方,又有太多不同的地方.很多人在初学的 ...
- 深入理解Java的接口和抽象类
深入理解Java的接口和抽象类 对于面向对象编程来说,抽象是它的一大特征之一.在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类.这两者有太多相似的地方,又有太多不同的地方.很多人在初学的 ...
- java微信接口之五—消息分组群发
一.微信消息分组群发接口简介 1.请求:该请求是使用post提交地址为: https://api.weixin.qq.com/cgi-bin/message/mass/sendall?access_t ...
随机推荐
- WEB漏洞——PHP反序列化
序列化 首先说说什么是序列化 序列化给我们传递对象提供了一种简单的方法.serialize()将一个对象转换成一个字符串,并且在转换的过程中可以保存当前变量的值 而反序列化unserialize()将 ...
- Postman调试Abp API
在swagger中查看登录需要用post方式访问,Abp需要用application/json方式调用 请求体 Postman调用方式 例:访问所有用户,调用Api地址为http://localhos ...
- iframe 内容适用高度
HTML: <div class="content"> <iframe id="frameObj" src="链接" fr ...
- hyperf从零开始构建微服务(二)——构建服务消费者
阅读目录 构建服务消费者 安装json rpc依赖 安装JSON RPC客户端 server配置 编写业务代码 编写服务消费者类 consumer配置 配置 UserServiceInterface ...
- 使用tasker定时打开一耳光应用
比如现在要做一个:到9点钟自动打开"酷狗音乐"1.任务→点击"+"→填写"打开酷狗音乐"→点击"√"2.任务编辑→点击& ...
- Spirit带你彻底了解事件捕获和冒泡机制
Dom标准事件模型 在Dom标准事件模型中,事件是先进行捕获,达到目标阶段时,在进行冒泡的 捕获阶段==>目标阶段==>冒泡阶段 目标元素和非目标元素 在介绍事件捕获和事件冒泡前 我们先要 ...
- 剑指offer计划19( 搜索与回溯算法中等)---java
1.1.题目1 剑指 Offer 64. 求1+2+-+n 1.2.解法 这题看评论区真的绝了,都是人才,各个说话都好听,我看到个还有用异常来结束的就离谱. 这题用了&&当左边为fal ...
- Spring Cloud Hystrix 学习(一)
在学习Hystrix之前,首先引入一个问题场景,服务雪崩.如下图所示: 可以看到,三个入口服务A.B.C最终都会请求到服务T.当服务T的请求过载,打满CPU都无法匹配请求的频率时,同步调用的上级服务就 ...
- Shell系列(13)- read
前言 作用是往脚本中传递参数,之前文章的位置参数变量也有此功能,但是只适用于脚本的作者,为什么?第三方用户不知道这个脚本要传递哪些参数,这些参数分别是什么.本篇随笔read就可以实现上述功能,别且该命 ...
- Linux档案权限篇(一)
查看档案的属性"ls-al". 即列出所有的档案的详细权限与属性(包括隐藏文件) 权限 第一个字符代表档案的类型: d:代表是目录 -:代表是文件 l:代表是连接文件(相当于win ...