Java集合框架——Set接口
第三阶段 JAVA常见对象的学习
集合框架——Set接口
List集合的特点是有序的,可重复的,是不是存在这一种无序,且能保证元素唯一的集合呢?(HashSet )这就涉及到我们今天所要讲的Set集合
Set可以理解为行为不同的Collection
(一) 概述及功能
(1) 概述
Collection
List —— 有序(存储顺序和取出顺序一致),可重复
**Set **—— 无序(存储顺序和取出顺序不一致),唯一
我们首先要清楚有序无序,到底是什么意思?
集合所说的序,是指元素存入集合的顺序,当元素存储顺序和取出顺序一致时就是有序,否则就是无序。
我们一般说的无序是指HashSet,它既不能保证存储和取出顺序一致,更不能保证自然顺序(a-z),而TreeSet 是可以实现自然顺序的。(HashSet的有无序问题可是个大问题,下一篇专篇讲解)
(2) 功能
A:基本功能:(继承而来)
//添加功能
boolean add(E e):如果指定的元素不存在,则将其指定的元素添加(可选操作)
boolean addAll(Collection<? extends E> c):将指定集合中的所有元素添加到此集合
//删除功能
void clear():移除集合中的所有元素
boolean remove(Object o):从集合中移除指定的元素
boolean removeAll(Collection<?> c):从集合中移除一个指定的集合元素(有一个就返回true)
//长度功能
int size();
//判断功能
boolean isEmpty():判断集合是否为空
boolean contains(Object o):判断集合中是否包含指定元素
boolean containsAll(Collection<?> c):判断集合中是否包含指定的一个集合中的元素
boolean retainAll(Collection<?> c):仅保留该集合中包含在指定集合中的元素
//获取Set集合的迭代器:
Iterator<E> iterator();
//把集合转换成数组
Object[] toArray():返回一个包含此集合中所有元素的数组
<T> T[] toArray(T[] a):同上,返回的数组的运行时类型是指定数组的运行时类型
B:特有功能:
//判断元素是否重复,为子类提高重写方法
boolean equals(Object o):将指定的对象与此集合进行比较以实现相等
int hashCode();:返回此集合的哈希码值
Set集合中的方法用法并不难,可以参照前面Collection、List集合的讲解,对照学习,我们重点讲解Set中一些重要的特点。
(二) HashSet
一句话记住它:一种没有重复元素的无序集合
我们先说说无序是怎么回事,HashSet 它不保证 set 的迭代顺序,特别是它不保证该顺序恒久不变,也就是说它的存储顺序和取出顺序不一致,虽然说它无序,但是,作为集合来说,它肯定有它自己的存储顺序,而你的顺序恰好和它的存储顺序一致,这代表不了有序。下一篇专篇讲解这一问题!
无序问题由于篇幅较长,我们先放到另一边
我们先来思考一下,HashSet是如何保证不重复的呢?
通过查看HashSet中add方法的源码
// HashSet 源码节选-JKD8
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
我们可以看到HashSet中add方法所调用的是HashMap中的put方法,我们定位过去
由于解释篇幅较长,直接给出结论,具体源码解释在HashMap源码分析中具体讲解
这个方法底层主要依赖 两个方法:hashCode()和equals()。
步骤:
HashSet方法调用add方法时,调用hashCode(),得到一个哈希值,判断哈希值是否相同。
相同:执行equals()方法
返回true:说明元素重复,就不添加
返回false:说明元素不重复,就添加到集合
- 不同:就直接把元素添加到集合
现在大家可能想问一句,只使用hashCode()来判断是否重复可以吗?答案是否定的
我们给出这样一句话:
对象相等则hashCode一定相等,hashCode相等对象未必相等,只有equals返回true,hashCode才相等
- 如果类没有重写这两个方法,默认使用的Object()。一般来说不会相同。
- 而String类重写了hashCode()和equals()方法,所以,它就可以把内容相同的字符串去掉。只留下一个。
- 对于String 类型来说,不用重写 hashCode()方法和equals()方法都可以保证元素的唯一性,但是如果不是Stirng,而是其它自定义的对象就要重写这两个方法才能保证元素的唯一性。
(三) TreeSet
概述:
TreeSet:底层是二叉树结构(红黑树是一种自平衡的二叉树)
如何存储
那么这一种结构又是如何存储元素的呢?(我们将上图中圆圈称为节点)
- 第一个元素存储的时候,直接作为根节点存储
- 第二个元素开始,每个元素从根节点开始比较
- 若大 则作为右孩子
- 若小 则作为左孩子
- 相等 则不作处理
我们来举一个例子看看:
import java.util.Set;
import java.util.TreeSet;
public class TreeSetDemo {
public static void main(String[] args) {
Set<Integer> ts = new TreeSet<Integer>();
ts.add(20);
ts.add(18);
ts.add(23);
ts.add(22);
ts.add(17);
ts.add(24);
ts.add(19);
ts.add(18);
ts.add(24);
for (Integer i : ts) {
System.out.print(i + " ");
}
}
}
//运行结果
17 18 19 20 22 23 24
我们使用图片来解释一下上面的代码
我们将第一个数字20 作为根节点存放,第二个数字18比20小所以放在左边 23大放在右边
例如22这个数字是如何放到如图的位置呢?
首先22先和20比较是大的所以放到右边,接着继续和23进行比较是小的,所以放到23的左边,接下来同理
我们看到运行结果,很神奇的是按照顺序输出的,这也正符合了我们一开始给出的结论:TreeSet 是可以实现自然顺序的
如何取出
那么TreeSet中元素是如何取出来的呢?
从根节点开始,按照左,中,右的原则依次取出元素即可
分析:我们的根节点是20,所以先看左边也就是18,但是下面还有子节点,我们继续看左边所以第一个数字就是17,然后再看中和右也就是18和19,这时候根节点的左边也就全部看完了,所以接着就是中间的根节点20,右边同理。
如何存储自定义对象
我们设定一种场景,存储学生类中的学生对象,并且按照年龄从小到大排序(自然排序)
当满足所有成员变量的值都相同的时候即为同一个元素
注意:如果一个类的元素要想能够进行自然排序,就必须实现自然排序接口(关键)
public class Student implements Comparable<Student> {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Student s) {
//按照年龄排序
//年龄相同的时候,去看姓名是否也相同
//String 默认实现了Comparavle接口,所以可以直接使用字符串的compareTo方法
int num = this.age - s.age;
int num2 = num == 0 ? this.name.compareTo(s.name) : num;
return num2;
}
}
import java.util.Set;
import java.util.TreeSet;
public class StudentDemo {
public static void main(String[] args) {
Set<Student> ts = new TreeSet<Student>();
Student s1 = new Student("张三",27);
Student s2 = new Student("李四",16);
Student s3 = new Student("王五",40);
Student s4 = new Student("马六",40);
Student s5 = new Student("马六",40);
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
for (Student s : ts){
System.out.println(s);
}
}
}
//运行结果
Student{name='李四', age=16}
Student{name='张三', age=27}
Student{name='王五', age=40}
Student{name='马六', age=40}
我们可以专门定义了一个类MyComparator,其实也可以省略这一个类,直接在TreeSetDemo测试类中定义一个匿名内部类
package cn.bwh_04_TreeSet;
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
public class StudentDemo2 {
public static void main(String[] args) {
Set<Student2> ts = new TreeSet<Student2>(new Comparator<Student2>() {
@Override
public int compare(Student2 s1, Student2 s2) {
//姓名长度
int num = s1.getName().length() - s2.getName().length();
//姓名内容
int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
//年龄
int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
return num3;
}
});
Student2 s1 = new Student2("张三", 27);
Student2 s2 = new Student2("李四", 16);
Student2 s3 = new Student2("王五", 40);
Student2 s4 = new Student2("马六", 40);
Student2 s5 = new Student2("马六", 40);
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
for (Student2 s : ts) {
System.out.println(s);
}
}
}
Collection 集合总结
Collection集合应用时的选择
是否唯一
- 唯一:Set
- 需要排序:TreeSet
- 不需要排序:HashSet
- 如果你知道是Set,但是不知道是哪个Set,就用HashSet。
- 不唯一:List
- 需要安全:Vector
- 不需要安全:ArrayList或者LinkedList
- 查询多:ArrayList
- 增删多:LinkedList
如果三原则
如果你知道是List,但是不知道是哪个List,就用ArrayList。
如果你知道是Collection集合,但是不知道使用谁,就用ArrayList。
如果你知道用集合,就用ArrayList。
在集合中常见的数据结构
ArrayXxx:底层数据结构是数组,查询快,增删慢
LinkedXxx:底层数据结构是链表,查询慢,增删快
HashXxx:底层数据结构是哈希表。依赖两个方法:hashCode()和equals()
TreeXxx:底层数据结构是二叉树。两种方式排序:自然排序和比较器排序
结尾:
如果内容中有什么不足,或者错误的地方,欢迎大家给我留言提出意见, 蟹蟹大家 !_
如果能帮到你的话,那就来关注我吧!(系列文章均会在公众号第一时间更新)
在这里的我们素不相识,却都在为了自己的梦而努力 ❤
一个坚持推送原创Java技术的公众号:理想二旬不止
Java集合框架——Set接口的更多相关文章
- Java集合框架——List接口
第三阶段 JAVA常见对象的学习 集合框架--List接口 按照集合框架的继承体系,我们先从Collection中的List接口开始学习 (一) 概述及功能(ArrayList演示) (1) 概述 L ...
- Java集合框架之接口Collection源码分析
本文我们主要学习Java集合框架的根接口Collection,通过本文我们可以进一步了解Collection的属性及提供的方法.在介绍Collection接口之前我们不得不先学习一下Iterable, ...
- Java集合框架Map接口
集合框架Map接口 Map接口: 键值对存储一组对象 key不能重复(唯一),value可以重复 常用具体实现类:HashMap.LinkedHashMap.TreeMap.Hashtable Has ...
- Java集合框架顶层接口collectiion接口
如何使用迭代器 通常情况下,你会希望遍历一个集合中的元素.例如,显示集合中的每个元素. 一般遍历数组都是采用for循环或者增强for,这两个方法也可以用在集合框架,但是还有一种方法是采用迭代器遍历集合 ...
- Java集合框架——Map接口
第三阶段 JAVA常见对象的学习 集合框架--Map集合 在实际需求中,我们常常会遇到这样的问题,在诸多的数据中,通过其编号来寻找某一些信息,从而进行查看或者修改,例如通过学号查询学生信息.今天我们所 ...
- JAVA集合框架 - Map接口
Map 接口大致说明(jdk11): 整体介绍: 一个将键映射到值的(key-value)对象, 键值(key)不能重复, 每个键值只能影射一个对象(一一对应). 这个接口取代了Dictionary类 ...
- Java集合框架的接口和类层次关系结构图
Collection和Collections的区别 首先要说的是,"Collection" 和 "Collections"是两个不同的概念: 如下图所示,&qu ...
- Java集合框架之接口Iterator
简述 Iterator迭代器的定义:迭代器(Iterator)模式,又叫做游标(Cursor)模式.GOF给出的定义是,提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象 ...
- Lambda表达式和Java集合框架
本文github地址 前言 我们先从最熟悉的Java集合框架(Java Collections Framework, JCF)开始说起. 为引入Lambda表达式,Java8新增了java.util. ...
随机推荐
- 019-020_STM32程序移植之_W5500连接noenet
(一)本次实验是将数据通过W5500模块传输到onenet平台上面去 (二)显示内容,onenet平台数据变化曲线 (三)相关网站: 1.onenet网站:https://open.iot.10086 ...
- 000_linux之Ubuntu安装
今天2018/6/1 今天是六一儿童节,天气凉爽,心情挺好的.然后本着开开心心的心情,将前面忘记写linux的Ubuntu没安装的写一下,以后自己回来看就很方便了.使用的是白问网制作的ubuntu,假 ...
- sql server 存储过程和视图的区别
视图 要把视图看做是一张表,包含了一张表的部分数据或者多个表的综合数据,视图的使用和普通表一样: 视图建立并存储在服务器,有效减少网络数据流量,提高安全性: 视图中不存放数据,数据依然存放在视图引用的 ...
- springboot2.0最精简的配置yml
https://blog.csdn.net/yu_hongrun/article/details/81708762
- BZOJ 4025 二分图 LCT维护最大生成树
怎么说呢,我也不知道该咋讲,你就手画一下然后 yy 一下就发现这么做是对的. 为什么我明明都想出来了,却还是讲不出来啊~ #include <cstdio> #include <ve ...
- idea快捷方式1
Ctrl+Alt+O 优化导入的类和包 Alt+Insert 生成代码(如get,set方法,构造函数等) 或者右键(Generate) fori/sout/psvm + Tab Ctrl+Alt ...
- 内存管理3- @property 参数详解
@property ----------------- Create two classes: Book & Student ------------------- book.m #impor ...
- mapreduce 倒序 排序 最简单 易上手
对于mapreduce倒序只需要建立一个类,然后继承WritableComparator 在重写 Compare函数最后在main里调用一下,就可以实现倒序排序: 代码: public static ...
- JavaWeb_(Spring框架)Spring中IoC与DI概念入门
Spring是于2003 年兴起的一个轻量级的Java 开源框架,它由Rod Johnson创建.传统J2EE应用的开发效率低,Spring作为开源的中间件,提供J2EE应用的各层的解决方案,Spri ...
- JavaScript Call函数原理
call原理分析,一定要看最后的例子. 1.call使用例子 function add(c, d) { return this.a + this.b + c + d; } , b: }; consol ...