Java 数据类型:集合接口Collection之Set接口HashSet类;LinkedHashSet;TreeSet 类
Collection 之 Set
实现类:
- HashSet
- TreeSet
特点:
- 无序。
- 元素不可重复。
(如果试图添加一个已经有的元素到一个Set集合中,那么会添失败,add()方法返回false,且新元素不会被加入)
HashSet:
- 元素的值可以是null。
- HashSet是不同步的,如果有多个线程访问一个HashSet我们必须通过代码来保证同步?
底层架构:
- 底层是HashMap;
- HashSet 就是HashMap键的集合
HashSet<String > hashSet = new HashSet<>();
/*
* HashSet底层是HashMap
*/ //源码HahsSet的构造方法: public HashSet() {
map = new HashMap<>();
}
import java.util.Collection;
import java.util.HashSet;
import java.util.Set; /**
* @ClassName HashSetExample
* @projectName: object1
* @author: Zhangmingda
* @description: XXX
* date: 2021/4/9.
*/
public class HashSetExample {
public static void main(String[] args) {
Set persons = new HashSet();
persons.add("张三");
persons.add("李四");
persons.add("王五");
System.out.println(persons); //[李四, 张三, 王五]
}
}
hashSet添加元素流程解析:
- hashCode不同,不再调用equals判断元素是否相同。
- hashCode相等,但是equals返回的是false,那么我们会在相同的位置添加两个元素(通过链表的方法存储)。
- hashCode相等,equals返回也为true,不存储。
注意了,一般在开发的时候,为了判断两个元素是否相等,我们需要重写equals和hashCode,并且要保证equals和hashCode的一致性,如果equals返回为true,那么他们的hashCode应该要相等

示例代码:
import java.io.PrintStream;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set; /**
* @ClassName Hash
* @projectName: object1
* @author: Zhangmingda
* @description: XXX
* date: 2021/4/9.
*/
public class HashSetDecideEqualsExample {
public static class User{
private String name; public User(String name) {
this.name = name;
} @Override
public boolean equals(Object o) {
System.out.println("调用equals");
// if (this == o) return true;
// if (o == null || getClass() != o.getClass()) return false;
// User user = (User) o;
// return Objects.equals(name, user.name);
return true;
} @Override
public int hashCode() {
System.out.println("调用hashCode");
return Objects.hash(name);
// return 1;
} @Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
} public static void main(String[] args) {
Set persons = new HashSet(); persons.add(new User("张三"));
persons.add(new User("李四"));
persons.add(new User("张三"));
persons.add(new User("王五"));
System.out.println(persons);
}
}
/**
* 输出如下:User张三hashCode相同,然后调用了equals,判断是否相同,仍相同,第二个张三User未添加
调用hashCode
调用hashCode
调用hashCode
调用equals
调用hashCode
[User{name='李四'}, User{name='张三'}, User{name='王五'}]
*/
LinkedHashSet:
- LinkedHashSet是HashSet的一个子类,LinkedHashSet集合也是根据元素的hashCode值来决定元素的存储位置
- 有序:它使用链表维护元素的次序,这样使得元素看起来是以插入顺序保存的。当遍历LinkedHashSet集合里面的元素时,LinkedHashSet将会按照元素的添加顺序来访问集合里的元素。
- 性能:略低于HashSet的性能,但迭代访问Set里面的元素的时候新能会更好,因为用链表维护了内部的顺序。
import java.util.LinkedHashSet; public class LinkHashSetExample {
public static void main(String[] args) {
LinkedHashSet linkedHashSet = new LinkedHashSet();
linkedHashSet.add("d");
linkedHashSet.add("a");
linkedHashSet.add("c");
linkedHashSet.add(3);
linkedHashSet.add(2);
linkedHashSet.add(8);
System.out.println(linkedHashSet);//[d, a, c, 3, 2, 8]
}
}
TreeSet 类
特点:添加元素时自动排序
- 向TreeSet集合中添加元素就是吧元素作为键添加到底层的TreeMap中;
- TreeSet 就是TreeMap键的集合
- SortedSet:接口要求集合中元素必须是可比较的(要求元素的类实现Comparator接口)
与HashSet集合相比,TreeSet还提供了以下几个额外的方法:
- Comparator comparator():如果TreeSet采用了定制排序,则该方法返回定制排序所使用的Comparator,如果采用TreeSet自然排序,那么返回null。
- Object first():返回集合中第一个元素
- Object last():返回集合中的最后一个元素
- Object lower(Object e):返回集合中指定位于指定元素之前的元素。
- Object higher(Object e):返回集合中位于指定元素之后的元素。
- SortedSet subSet(Object fromElement, Object toElement): 返回此Set的子集合,范围从fromElement(包含)到toElement(不包含)。
- SortedSet headSet(Object toElement):返回此Set的子集,由小于toElement的元素组成。
- SortedSet tailSet(Object fromElement):返回此Set的子集,由大于或者等于fromElement的元素组成。
【排序逻辑】
TreeSet中,判断是否同一个元素,根据Comparator/Comparable的比较结果返回是否为0,如果比较结果为0 认为是相同元素。
在使用treeSet时,既可以在构造方法中指定Comparator类的匿名对象,也可以让元素的类实现Comparable接口。对TreeSet来说,他是先选择的Comparator,没有Comparator再选择Comparable。
- 对于程序员来说,实现Comparable接口重写CompareTo方法进行排序,或者做相等判断。一般定义一个比较广泛的比较规则。可以通过在构造方法中指定Comparator定义各种不同的比较规则
自定义添加元素排序逻辑
场景1、在TreeSet构造方法中指定Comparator比较器.-->示例代码设置逆序排序
public class TreeSetTest {
public static void main(String[] args) {
TreeSet<String> treeSet = new TreeSet<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.compareTo(o1);
}
});
treeSet.add("c");
treeSet.add("b");
treeSet.add("d");
treeSet.add("a");
System.out.println(treeSet);//[d, c, b, a]
}
}
import java.util.Comparator;
import java.util.TreeSet; /**
* @ClassName TreeSetSortExample
* @projectName: object1
* @author: Zhangmingda
* @description:
* date: 2021/4/10.
*/
public class TreeSetSortExample {
public static class User {
int age; public User(int age) {
this.age = age;
} @Override
public String toString() {
return "User{" +
"age=" + age +
'}';
} public static void main(String[] args) {
//创建TreeSet时自定义排序方法
// TreeSet<User> users1 = new TreeSet<>(new Comparator<User>() {
// @Override
// public int compare(User user, User t1) {
// return t1.age - user.age; //逆序
// }
// });
TreeSet<User> users1 = new TreeSet<>((User u1,User u2) ->{return u2.age - u1.age;});//逆序
users1.add(user1);
users1.add(user);
users1.add(user2);
users1.add(user3);
System.out.println(users1); //[User{age=88}, User{age=7}, User{age=2}, User{age=-8}]
}
}
场景2、要求自定义元素的类实现Comparator接口
import java.util.TreeSet; /**
* @ClassName TreeSetSortExample
* @projectName: object1
* @author: Zhangmingda
* @description: XXX
* date: 2021/4/10.
*/
public class TreeSetSortExample {
public static class User implements Comparable {
int age; public User(int age) {
this.age = age;
} @Override
public String toString() {
return "User{" +
"age=" + age +
'}';
} @Override
public int compareTo(Object o) {
User user = (User) o;
return this.age - user.age;
}
} public static void main(String[] args) {
TreeSet<User> users = new TreeSet<>();
User user = new User(2);
User user1 = new User(7);
User user2 = new User(88);
User user3 = new User(-8);
users.add(user1);
users.add(user);
users.add(user2);
users.add(user3);
System.out.println(users); //[User{age=-8}, User{age=2}, User{age=7}, User{age=88}]
}
}
EnumSet:
- EnumSet allOf(Class elementType): 创建一个包含指定枚举类里所有枚举值的EnumSet集合。
- EnumSet complementOf(EnumSet e): 创建一个其元素类型与指定EnumSet里元素类型相同的EnumSet集合,新EnumSet集合包含原EnumSet集合所不包含的、此类枚举类剩下的枚举值(即新EnumSet集合和原EnumSet集合的集合元素加起来是该枚举类的所有枚举值)。
- EnumSet copyOf(Collection c): 使用一个普通集合来创建EnumSet集合。
- EnumSet copyOf(EnumSet e): 创建一个指定EnumSet具有相同元素类型、相同集合元素的EnumSet集合。
- EnumSet noneOf(Class elementType): 创建一个元素类型为指定枚举类型的空EnumSet。
- EnumSet of(E first,E…rest): 创建一个包含一个或多个枚举值的EnumSet集合,传入的多个枚举值必须属于同一个枚举类。
- EnumSet range(E from,E to): 创建一个包含从from枚举值到to枚举值范围内所有枚举值的EnumSet集合。
import java.util.EnumSet; public class EnumSetTest {
private static enum Season {
SPRINT, SUMMER, FALL, WINTER
}
public static void main(String[] args) {
EnumSet es1 = EnumSet.allOf(Season.class);
System.out.println(es1);
EnumSet es2 = EnumSet.noneOf(Season.class);
System.out.println(es2);
es2.add(Season.SUMMER);
es2.add(Season.FALL);
System.out.println(es2);
}
}
Set性能分析:
public class TreeSetTest02 {
public static void main(String[] args) {
//定义一个TreeSet集合存储Person,在TreeSet构造方法中指定Comparator比较器,根据年龄降序排序
TreeSet<Person> treeSet = new TreeSet<>(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o2.getAge() - o1.getAge();
}
});
treeSet.add(new Person("zhangsan",20));
treeSet.add(new Person("lisi",23));
treeSet.add(new Person("wangwu",14));
treeSet.add(new Person("zhaoliu",35));
treeSet.add(new Person("tiaoqi",57));
System.out.println(treeSet.contains(new Person("Shabi",14)));//true
//这里根据Comparator比较器返回 0 即认为是同一个元素
TreeSet<Person> treeSet1 = new TreeSet<>();
//如果没有在构造方法指定Comparator比较器,要求元素的类实现Comparator接口
treeSet1.add(new Person("zhangsan",20));
treeSet1.add(new Person("lisi",23));
treeSet1.add(new Person("wangwu",14));
treeSet1.add(new Person("zhaoliu",35));
treeSet1.add(new Person("tiaoqi",57));
System.out.println(treeSet1.contains(new Person("Shabi",14)));//false
System.out.println(treeSet1);
}
}
//Person类实现Comparable接口,通过Comparable<Person>泛型指定比较元素的数据类型也是Persion
class Person implements Comparable<Person> {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", 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 int compareTo(Person o) {
if (this.age == o.getAge() && this.name == o.getName()){
return 0;}
else
return this.name.compareTo(o.getName());
//集合中存储多个对象的时候,根据返回值是否是0判断是否是同一个对象
}
}
Java 数据类型:集合接口Collection之Set接口HashSet类;LinkedHashSet;TreeSet 类的更多相关文章
- Java集合概述、Set集合(HashSet类、LinkedHashSet类、TreeSet类、EnumSet类)
Java集合概述.Set集合(HashSet类.LinkedHashSet类.TreeSet类.EnumSet类) 1.Java集合概述1)数组可以保存多个对象,但数组长度不可变,一旦在初始化数组时指 ...
- java集合 之 Collection和Iterator接口
Collection是List,Queue和Set接口的父接口,该接口里定义的方法即可用于操作Set集合,也可以用于List和Queue集合.Collection接口里定义了如下操作元素的方法. bo ...
- Java:集合,Collection接口框架图
Java集合大致可分为Set.List和Map三种体系,其中Set代表无序.不可重复的集合:List代表有序.重复的集合:而Map则代表具有映射关系的集合.Java 5之后,增加了Queue体系集合, ...
- java集合(2)-Collection与Iterator接口
1 package com.j1803.collectionOfIterator; 2 import java.util.ArrayList; 3 import java.util.Collectio ...
- Java容器深入浅出之Collection与Iterator接口
Java中用于保存对象的容器,除了数组,就是Collection和Map接口下的容器实现类了,包括用于迭代容器中对象的Iterator接口,构成了Java数据结构主体的集合体系.其中包括: 1. Co ...
- java学习——集合框架(Collection,List,Set)
集合类的由来: 对象用于封装特有数据,对象多了需要存储,如果对象的个数不确定,就使用集合容器进行存储. 集合特点:1,用于存储对象的容器.2,集合的长度是可变的.3,集合中不可以存储基本数据类型值. ...
- 复习java基础第三天(集合:Collection、Set、HashSet、LinkedHashSet、TreeSet)
一.Collection常用的方法: Java 集合可分为 Set.List 和 Map 三种体系: Set:无序.不可重复的集合. List:有序,可重复的集合. Map:具有映射关系的集合. Co ...
- Java自学-集合框架 Collection
Java集合框架 Collection Collection是一个接口 步骤 1 : Collection Collection是 Set List Queue和 Deque的接口 Queue: 先进 ...
- [Java复习] 集合框架 Collection
Q1 Collection java的集合以及集合之间的继承关系? 数组和链表的区别? 固定长度,连续内存,不能扩展,随机访问快,插入删除慢.链表相反 List, Set, Map的区别? List, ...
随机推荐
- vscode 整理————开篇之力(一)
前言 作为一个开发为什么对一个vscode 这样的工具进行整理呢,因为vscode 非常的常用,它包含很多编辑器共同有的特征,这些特征帮助我们了解其他编辑器. 这里可能就有人疑问了,我们需要去非常的关 ...
- try catch引发的性能优化深度思考
关键代码拆解成如下图所示(无关部分已省略): 起初我认为可能是这个 getRowDataItemNumberFormat 函数里面某些方法执行太慢,从 formatData.replace 到 une ...
- Codeforces 986F - Oppa Funcan Style Remastered(同余最短路)
Codeforces 题面传送门 & 洛谷题面传送门 感谢此题教会我一个东西叫做同余最短路(大雾 首先这个不同 \(k\) 的个数 \(\le 50\) 这个条件显然是让我们对每个 \(k\) ...
- 模版 动态 dp
模版 动态 dp 终于来写这个东西了.. LG 模版:给定 n 个点的数,点有点权, $ m $ 次修改点权,求修改完后这个树的最大独立集大小. 我们先来考虑朴素的最大独立集的 dp \[dp[u][ ...
- 洛谷 P4646 - [IOI2007] flood 洪水(拆点+bfs)
题面传送门 一道挺有意思的题(?) orz djq yyds %%%%%%%%%%%%%%%%%% 首先一个很直观的想法是将每个房间看作一个节点,在有墙的房间旁边连边权为 \(1\) 的边然后 bfs ...
- 【基因组预测】braker2基因结构注释要点记录
目录 流程使用 问题 记录下braker2的使用要点,以备忘记. 流程使用 braker2有很多流程,根据你的数据:组装的基因组.转录组.蛋白(同源,包括近缘或远缘)选择不同流程,官网有说明: htt ...
- msyql_union
MySQL UNION 操作符用于连接两个以上的 SELECT 语句的结果组合到一个结果集合中.多个 SELECT 语句会删除重复的数据. 语法 MySQL UNION 操作符语法格式: SELECT ...
- perl练习——计算点突变
题目来源:http://rosalind.info/problems/hamm/ 一.程序目的:计算序列点突变(Point Mutations) 输入: GAGCCTACTAACGGGAT CATCG ...
- Ansi,UTF8,Unicode,ASCII编码的区别
Ansi,UTF8,Unicode,ASCII编码的区别 近日需要不同的编码,关于上述编码,一直迷迷糊糊,查了些资料,总算大致了解了, 下面全是从网上搜来的: 1. ASCII和Ansi编码 ...
- 前后端分离进阶一:使用ElementUI+前端分页
前两篇入门:前后端分离初体验一:前端环境搭建 前后端分离初体验二:后端环境搭建+数据交互 参考:https://www.bilibili.com/video/BV137411B7vB B站UP:楠哥教 ...