JavaSe·容器篇(四) Set集合
1. Set接口
java.util.Set 接口和 java.util.List 接口一样,同样继承自 Collection 接口,它与 Collection 接口中的方法基本一致,并没有对 Collection 接口进行功能上的扩充,只是比 Collection 接口更加严格了。与 List 接口不同的是, Set 接口中元素无序,并且都会以某种规则保证存入的元素不出现重复。
Set集合取出元素的方式可以采用:迭代器、增强for
2. HashSet集合
2.1 HashSet介绍
java.util.HashSet 是 Set 接口的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的(即存取顺序不一致)。 java.util.HashSet 底层的实现其实是一个 java.util.HashMap 支持
HashSet 是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能。保证元素唯一性的方式依赖于: hashCode 与 equals 方法。
public static void main(String[] args) {
//创建 Set集合
HashSet<String> set = new HashSet<String>();
//添加元素
set.add(new String("cba"));
set.add("abc");
set.add("bac");
set.add("cba");
//遍历
for (String name : set) {
System.out.println(name);
}
}
输出:
cba
abc
bac
根据结果我们发现字符串"cba"只存储了一个,也就是说重复的元素set集合不存储。
2.2 HashSet集合存储数据的结构——哈希表
在JDK1.8之前,哈希表底层采用数组+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而JDK1.8中,哈希表存储采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。
简单的来说,哈希表是由数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的:
2.3 HashSet存储原理图——即HashMap底层
总而言之,JDK1.8引入红黑树大程度优化了HashMap的性能,那么对于我们来讲保证HashSet集合元素的唯一,其实就是根据对象的hashCode和equals方法来决定的。如果我们往集合中存放自定义的对象,那么保证其唯一,就必须复写hashCode和equals方法建立属于当前对象的比较方式。
2.3 HashSet存储自定义类型元素
给HashSet中存放自定义类型元素时,需要重写对象中的hashCode和equals方法,建立自己的比较方式,才能保证HashSet集合中的对象唯一
创建自定义类
public class 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 boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
public static void main(String[] args) {
//创建集合对象 该集合中存储 Student类型对象
HashSet<Student> stuSet = new HashSet<Student>();
//存储
Student stu = new Student("于谦", 43);
stuSet.add(stu);
stuSet.add(new Student("郭德纲", 44));
stuSet.add(new Student("于谦", 43));
stuSet.add(new Student("郭麒麟", 23));
stuSet.add(stu);
for (Student stu2 : stuSet) {
System.out.println(stu2);
}
}
执行结果:
Student [name=郭德纲, age=44]
Student [name=于谦, age=43]
Student [name=郭麒麟, age=23]
3. LinkedHashSet
我们知道HashSet保证元素唯一,可是元素存放进去是没有顺序的,那么我们要保证有序,怎么办呢?在HashSet下面有一个子类 java.util.LinkedHashSet ,它是链表和哈希表组合的一个数据存储结构。
public static void main(String[] args) {
Set<String> set = new LinkedHashSet<String>();
set.add("bbb");
set.add("aaa");
set.add("abc");
set.add("bbc");
Iterator<String> it = set.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
4. TreeSet
TreeSet是SortedSet接口的唯一实现类,TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序 和定制排序,其中自然排序为默认的排序方式。向TreeSet中加入的应该是同一个类的对象。
4.1 TreeSet特点
1)底层数据结构是红黑树,即平衡二叉树,有序(这里的有序不是list的有序概念),实现非同步,内部功能实现依赖于TreeMap的方法。
2)该类返回的元素顺序并非是集合添加元素的顺序,而是按照某个排序算法排列的。该算法有两种情况,由创建TreeSet实例时所用的构造函数决定使用哪种顺序。
4.2 TreeSet数据结构——红黑树
二叉树:binary tree ,是每个结点不超过2的有序树(tree)
简单的理解,就是一种类似于我们生活中树的结构,只不过每个结点上都最多只能有两个子结点
二叉树是每个节点最多有两个子树的树结构。顶上的叫根结点,两边被称作“左子树”和“右子树”
我们要说的是二叉树的一种比较有意思的叫做红黑树,红黑树本身就是一颗二叉查找树,将节点插入后,该树仍然是一颗二叉查找树。也就意味着,树的键值仍然是有序的。
4.2 TreeSet集合两种实现排序方式
-
自然排序(元素具备比较性)
TreeSet的无参构造,要求对象所属的类实现Comparable接口。 -
比较器排序(集合具备比较性)
-
TreeSet的带参构造,要求构造方法接收一个实现了Comparator接口的对象。
4.3 自然排序——Comparable
Comparable:
- int compareTo(T o):比较此对象与指定对象的顺序。
class Student implements Comparable{
private String name;
private int age;
Student(String name,int age){
this.name=name;
this.age=age;
}
public int compareTo(Object obj){
if(!(obj instanceof Student)){
throw new RuntimeException("不是学生对象");
}
Student s = (Student)obj;
int num = this.age-s.age;
if(num==0) {
return this.name.comparTo(s.name);
} else {
return num;
}
}
// getter,setter..
// toString..
}
public static void main(String[] args){
TreeSet ts =new TreeSet();
ts.add(new Student("张三",21));
ts.add(new Student("王五",23));
ts.add(new Student("周七",19));
ts.add(new Student("赵六",18));
for(Iterator iter = ts.iterator();iter.hasNext();){
System.out.println(obj);
}
}
4.4 比较器排序——Comparator
Comparator:
- int compare(T o1, T o2) : 比较用来排序的两个参数。
- boolean equals(Object obj) :指示某个其他对象是否“等于”此 Comparator。
class Student {
private String name;
private int age;
Student(String name,int age){
this.name=name;
this.age=age;
}
// getter,setter..
// toString..
}
class MyCompare implements Comparator{
public int compare(Object obj1,Object obj2){
Student s1 = (Student)obj1;
Student s2 = (Student)obj2;
int num = new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
if(num==0) {
return s1.getName().compareTo(s2.getName());
}
return num;
}
}
public static void main(String[] args){
TreeSet ts =new TreeSet(new MyCompare());
ts.add(new Student("张三",21));
ts.add(new Student("王五",23));
ts.add(new Student("周七",19));
ts.add(new Student("赵六",18));
for(Iterator iter = ts.iterator();iter.hasNext();){
System.out.println(obj);
}
}
来源:CSDN
作者:不爱我就写代码
链接:https://blog.csdn.net/qq_41744145/article/details/100068643