系列文章

「 深入浅出 」集合List

「 深入浅出 」java集合Collection和Map

Set继承自Collection接口,不能包含有重复元素。本篇文章主要讲Set中三个比较重要的实现类:HashSet、TreeSet。

Set

Set是一个存储无序且不重复元素的集合。

在使用Set集合的时候,应该注意两点

  • 为Set集合里的元素的实现类重写equals()和hashCode()方法()

  • 若传入重复的元素,重复元素会被忽略(可以用于做集合的去重)

扩展

判断两个元素相等的标准:两个对象通过equals()方法比较相等,并且两个对象的hashCode()方法返回值也相等。

HashSet

HashSet是Set接口的典型实现,是哈希表结构,主要利用HashMap的key来存储元素,计算插入元素的hashCode来获取元素在集合中的位置,因此具有很好的存取和查找性能。

主要特点

1.不允许出现重复元素

2.存储的元素是无序的

3.不是同步的,如果多个线程同时访问一个HashSet,则必须通过代码来保证其同步。

4.集合元素值可以是null。

HashSet基本操作
public class HashSetTest {
public static void main(String[] agrs){
//创建HashSet集合:
Set<String> hashSet = new HashSet<String>();
System.out.println("HashSet初始容量大小:"+hashSet.size()); //元素添加:
hashSet.add("my");
hashSet.add("name");
hashSet.add("is");
hashSet.add("ken");
hashSet.add("hello");
hashSet.add("everyone");
System.out.println("HashSet容量大小:"+hashSet.size()); //迭代器遍历:
Iterator<String> iterator = hashSet.iterator();
while (iterator.hasNext()){
String str = iterator.next();
System.out.print(str+" ");
}
System.out.print("\n");
//元素删除:
hashSet.remove("ken");
System.out.println("HashSet元素大小:" + hashSet.size());
hashSet.clear();
System.out.println("HashSet元素大小:" + hashSet.size()); //集合判断:
boolean isEmpty = hashSet.isEmpty();
System.out.println("HashSet是否为空:" + isEmpty);
boolean isContains = hashSet.contains("hello");
System.out.println("HashSet是否为空:" + isContains);
}
}
//out:
HashSet初始容量大小:0
HashSet容量大小:6
ken everyone name is hello my
HashSet元素大小:5
HashSet元素大小:0
HashSet是否为空:true
HashSet是否为空:false

细节注意事项可看以下例子:

//重写类A的equals方法总是返回true,但没有重写其hashCode()方法。
//不能保证当前对象是HashSet中的唯一对象
class A {
@Override
public boolean equals(Object obj) {
return true;
}
} //重写类B的hashCode()方法总是返回1,但没有重写其equals()方法。
//不能保证当前对象是HashSet中的唯一对象
class B {
@Override
public int hashCode() {
return 1;
}
} //重写重写类C的hashCode()方法总是返回2,且有重写其equals()方法
class C {
@Override
public int hashCode() {
return 2;
} @Override
public boolean equals(Object obj) {
return true;
}
} public class HashSetTest {
public static void main(String[] args) {
HashSet books = new HashSet();
//分别向books集合中添加两个A对象,两个B对象,两个C对象
books.add(new A());
books.add(new A()); books.add(new B());
books.add(new B()); books.add(new C());
books.add(new C());
System.out.println(books);
}
}
//out
[B@1, B@1, C@2, A@3bc257, A@785d65]

可以看出,只有当同时重写了equals方法和hashCode方法时,才能按照自己的意图判断对象是否相等,否则均判定为不相等,可加入Set集合中。

TreeSet

与HashSet集合类似,TreeSet也是基于Map来实现,其底层结构为红黑树(特殊的二叉查找树)

与HashSet不同的是,TreeSet具有排序功能,分为自然排序(123456)和自定义排序两类,默认是自然排序

具有如下特点:

  • 对插入的元素进行排序,是一个有序的集合(主要与HashSet的区别)

  • 底层使用红黑树结构,而不是哈希表结构

  • 允许插入Null值

  • 不允许插入重复元素

  • 线程不安全

TreeSet基本操作
public class TreeSetTest {
public static void main(String[] agrs){
TreeSet<String> treeSet = new TreeSet<String>();
System.out.println("TreeSet初始化容量大小:"+treeSet.size()); //元素添加:
treeSet.add("my");
treeSet.add("name");
treeSet.add("ken");
treeSet.add("hello");
treeSet.add("world");
treeSet.add("1");
treeSet.add("2");
treeSet.add("3");
System.out.println("TreeSet容量大小:" + treeSet.size());
System.out.println("TreeSet元素顺序为:" + treeSet.toString()); System.out.println("遍历元素升序:");
//迭代器遍历:升序
Iterator<String> iteratorAesc = treeSet.iterator();
while(iteratorAesc.hasNext()){
String str = iteratorAesc.next();
System.out.print(str + " ");
}
System.out.println("\n");
System.out.println("遍历元素降序:");
//迭代器遍历:降序
Iterator<String> iteratorDesc = treeSet.descendingIterator();
while(iteratorDesc.hasNext()){
String str = iteratorDesc.next();
System.out.print(str + " ");
}
System.out.println("\n");
//元素获取:实现NavigableSet接口
String firstEle = treeSet.first();//获取TreeSet头节点:
System.out.println("TreeSet头节点为:" + firstEle); // 获取指定元素之前的所有元素集合:(不包含指定元素)
SortedSet<String> headSet = treeSet.headSet("ken");
System.out.println("ken节点之前的元素为:"+headSet.toString()); //获取给定元素之间的集合:(包含头,不包含尾)
SortedSet subSet = treeSet.subSet("1","hello");
System.out.println("1--hello之间节点元素为:"+subSet.toString()); //集合判断:
boolean isEmpty = treeSet.isEmpty();
System.out.println("TreeSet是否为空:"+isEmpty);
boolean isContain = treeSet.contains("who");
System.out.println("TreeSet是否包含who元素:"+isContain); //元素删除:
boolean kenRemove = treeSet.remove("ken");
System.out.println("ken元素是否被删除"+kenRemove); //集合中不存在的元素,删除返回false
boolean whoRemove = treeSet.remove("who");
System.out.println("who元素是否被删除"+whoRemove); //删除并返回第一个元素:如果set集合不存在元素,则返回null
String pollFirst = treeSet.pollFirst();
System.out.println("删除的第一个元素:"+pollFirst); //删除并返回最后一个元素:如果set集合不存在元素,则返回null
String pollLast = treeSet.pollLast();
System.out.println("删除的最后一个元素:"+pollLast); treeSet.clear();//清空集合
}
}
//out:
TreeSet初始化容量大小:0
TreeSet容量大小:8
TreeSet元素顺序为:[1, 2, 3, hello, ken, my, name, world]
遍历元素升序:
1 2 3 hello ken my name world 遍历元素降序:
world name my ken hello 3 2 1 TreeSet头节点为:1
ken节点之前的元素为:[1, 2, 3, hello]
1--hello之间节点元素为:[1, 2, 3]
TreeSet是否为空:false
TreeSet是否包含who元素:false
jiaboyan元素是否被删除false
who元素是否被删除false
删除的第一个元素:1
删除的最后一个元素:world
TreeSet元素排序

我们讲到了TreeSet是一个有序集合,可以对集合元素排序,其中分为自然排序和自定义排序

自然排序(正序与反序)
public class TreeSetTest {
public static void main(String[] agrs){
TreeSet<String> treeSetString = new TreeSet<String>();
treeSetString.add("a");
treeSetString.add("z");
treeSetString.add("d");
treeSetString.add("b");
System.out.println("字母正序:" + treeSetString.toString());
System.out.println("字母反序:" + treeSetString.descendingSet().toString()); TreeSet<Integer> treeSetInteger = new TreeSet<Integer>();
treeSetInteger.add(1);
treeSetInteger.add(24);
treeSetInteger.add(23);
treeSetInteger.add(6);
System.out.println("数字正序:" + treeSetInteger.toString());
System.out.println("数字反序:" + treeSetInteger.descendingSet().toString());
}
}
//out
字母顺序:[a, b, d, z]
数字顺序:[1, 6, 23, 24]
自定义排序

当使用的是自己定义的类时,就需要做一些特殊处理,否则会报错Exception in thread "main" java.lang.ClassCastException,有两种实现方式

1.实现Comparable接口

public class Person implements Comparable<Person>{
private String name;
private Integer age;
public Person(){}
public Person(String name,Integer age){
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public int compareTo(Person person) {
//如果name长度一样,则比较年龄的大小
//需要考虑相等的情况,否则相等的情况只显示先加入集合的元素
if(this.age.equals(person.age)){
return 1;
}
return this.age - person.age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
} public static void main(String[] agrs){
TreeSet<Person> treeSet = new TreeSet<Person>(); //排序对象:
Person p1 = new Person("ken",18);
Person p2 = new Person("xiaoming",15);
Person p3 = new Person("laowang",15);
Person p4 = new Person("zhangsan",25); //添加到集合:
treeSet.add(p1);
treeSet.add(p2);
treeSet.add(p3);
treeSet.add(p4);
System.out.println("TreeSet集合顺序为:"+treeSet);
} }
//out:
TreeSet集合顺序为:[Person{name='xiaoming', age=15}, Person{name='laowang', age=15},
Person{name='ken', age=18}, Person{name='zhangsan', age=25}]
2.实现Comparetor接口,并重写compare方法
//自定义Person类的比较器:
public class PersonComparator implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
//比较名字长度,从大到小排序
//需要考虑相等的情况,否则相等的情况只显示先加入集合的元素
if(p2.getName().length() == p1.getName().length()){
return 1;
}
return p2.getName().length() - p1.getName().length();
}
}

测试程序

public static void main(String[] agrs){
TreeSet<Person> treeSet = new TreeSet<Person>(new PersonComparator()); //排序对象:
Person p1 = new Person("ken",18);
Person p2 = new Person("xiaoming",15);
Person p3 = new Person("laowang",15);
Person p4 = new Person("zhangsan",25); //添加到集合:
treeSet.add(p1);
treeSet.add(p2);
treeSet.add(p3);
treeSet.add(p4);
System.out.println("TreeSet集合顺序为:"+treeSet);
}
//out
TreeSet集合顺序为:[Person{name='xiaoming', age=15}, Person{name='zhangsan', age=25},
Person{name='laowang', age=15}, Person{name='ken', age=18}]

后续文章将对java集合中的具体实现类进行深入了解。有兴趣的话可以观看后续内容,进一步了解java集合内容。

推荐阅读: 个人网站模板推荐

如何在GitHub上大显身手?

IDEA热部署插件JRebel

坚持日更:7天

您的点赞、转发是对我最大的支持!

THANDKS

  • End -

一个立志成大腿而每天努力奋斗的年轻人

伴学习伴成长,成长之路你并不孤单!

「 深入浅出 」集合Set的更多相关文章

  1. 「 深入浅出 」集合Map

    系列文章: 「 深入浅出 」java集合Collection和Map 「 深入浅出 」集合List 「 深入浅出 」集合Set 前面已经介绍完了Collection接口下的集合实现类,今天我们来介绍M ...

  2. 「 深入浅出 」集合List

    第一篇文章 「 深入浅出 」java集合Collection和Map 主要讲了对集合的整体介绍,本篇文章主要讲List相对于Collection新增的一些重要功能以及其重要子类ArrayList.Li ...

  3. 「BZOJ2839」集合计数

    「BZOJ2839」集合计数 题目大意: 一个包含 \(n\) 个数的集合有 \(2^n\) 个子集,从这些子集中取出若干个集合(至少一个),使他们的交集的元素个数恰好为 \(k\),求方案数,答案对 ...

  4. 「 深入浅出 」java集合Collection和Map

    本系列文章主要对java集合的框架进行一个深入浅出的介绍,使大家对java集合有个深入的理解. 本篇文章主要具体介绍了Collection接口,Map接口以及Collection接口的三个子接口Set ...

  5. 「Foundation」集合

    一.NSArray和NSMutableArray (一)NSArray不可变数组 (1)NSArray的基本介绍 NSArray是OC中使用的数组,是面向对象的,以面向对象的形式操纵对象,是不可变数组 ...

  6. 「2014-3-17」C pointer again …

    记录一个比较基础的东东-- C 语言的指针,一直让人又爱又恨,爱它的人觉得它既灵活又强大,恨它的人觉得它太过于灵活太过于强大以至于容易将人绕晕.最早接触 C 语言,还是在刚进入大学的时候,算起来有好些 ...

  7. Loj #3096. 「SNOI2019」数论

    Loj #3096. 「SNOI2019」数论 题目描述 给出正整数 \(P, Q, T\),大小为 \(n\) 的整数集 \(A\) 和大小为 \(m\) 的整数集 \(B\),请你求出: \[ \ ...

  8. Loj #2542. 「PKUWC2018」随机游走

    Loj #2542. 「PKUWC2018」随机游走 题目描述 给定一棵 \(n\) 个结点的树,你从点 \(x\) 出发,每次等概率随机选择一条与所在点相邻的边走过去. 有 \(Q\) 次询问,每次 ...

  9. 一个「学渣」从零开始的Web前端自学之路

    从 13 年专科毕业开始,一路跌跌撞撞走了很多弯路,做过餐厅服务员,进过工厂干过流水线,做过客服,干过电话销售可以说经历相当的“丰富”. 最后的机缘巧合下,走上了前端开发之路,作为一个非计算机专业且低 ...

随机推荐

  1. <% %>、<%! %>和<%= %>

    <%  %> 此标签内的内容在jsp编译的时候,将被编译成servlet的_jspService()方法.这个方法用作服务器端向客户端输出.因此这对标签里边不能在定义方法了,因为在Java ...

  2. 前端工具--利用Adblock Plus阻止js执行

    今天遇到个问题:需要阻止页面某个js的运行 效果达到

  3. Java面向对象程序设计第8章3-5

    Java面向对象程序设计第8章3-5 3.String类型有什么特点? 一旦赋值,便不能更改其指向的字符对象 如果更改,则会指向一个新的字符对象 不能为null 4.String什么时候进行值比较,什 ...

  4. vue项目使用websocket做聊天项目总结

    一.首先我们先了解一下websocket的使用: 1.创建websocket const ws = new WebSocket("ws://192.168.31.136:9998/ws&qu ...

  5. 关于python2和python3除法的区别

    在Python2中,除法的取值结果取整数 >>> 9/2 4 而在Python3中,除法/的结果包含小数,如果只想取整数需要使用// >>> 9/2 4.5 > ...

  6. asp.net core 3.x Endpoint终结点路由1-基本介绍和使用

    前言 我是从.net 4.5直接跳到.net core 3.x的,感觉asp.net这套东西最初是从4.5中的owin形成的.目前官方文档重点是讲路由,没有特别说明与传统路由的区别,本篇主要介绍终结点 ...

  7. 【一起学源码-微服务】Nexflix Eureka 源码八:EurekaClient注册表抓取 精妙设计分析!

    前言 前情回顾 上一讲 我们通过单元测试 来梳理了EurekaClient是如何注册到server端,以及server端接收到请求是如何处理的,这里最重要的关注点是注册表的一个数据结构:Concurr ...

  8. 洛谷$P4149\ [IOI2011]\ Race$ 点分治

    正解:点分治 解题报告: 传送门$QwQ$ 昂先不考虑关于那个长度的限制考虑怎么做? 就开个桶,记录所有边的取值,每次加入边的时候查下是否可行就成$QwQ$ 然后现在考虑加入这个长度的限制?就考虑把这 ...

  9. Python+appium+unittest UI自动化测试

    什么是UI自动化 自动化分层 单元自动化测试,指对软件中最小可测试单元进行检查和验证,一般需要借助单元测试框架,如java的JUnit,python的unittest等 接口自动化测试,主要检查验证模 ...

  10. React useEffect的源码解读

    前言 对源码的解读有利于搞清楚Hooks到底做了什么,如果您觉得useEffect很"魔法",这篇文章也许对您有些帮助. 本篇博客篇幅有限,只看useEffect,力求简单明了,带 ...