HashSet
HashSet是Set接口的典型实现,实现了Set接口中的所有方法,并没有添加额外的方法,大多数时候使用Set集合时就是使用这个实现类。HashSet按Hash算法来存储集合中的元素。因此具有很好的存取和查找性能。
特点
- 不能保证元素的排列顺序,顺序可能与添加顺序不同,顺序也有可能发生变化。
- HashSet不是同步的,如果多个线程同时访问一个HashSet,则必须通过代码来保证其同步。
- 集合元素值可以是null。
- HashSet的实质是一个HashMap。HashSet的所有集合元素,构成了HashMap的key,其value为一个静态Object对象。因此HashSet的所有性质,HashMap的key所构成的集合都具备。
除此之外,HashSet判断两个元素是否相等的标准也是其一大特点。HashSet集合判断两个元素相等的标准是两个对象通过equals()方法比较相等,并且两个对象的hashCode()方法返回值也相等。
LinkedHashSet
LinkedHashSet是HashSet对的子类,也是根据元素的hashCode值来决定元素的存储位置,同时使用链表维护元素的次序,使得元素是以插入的顺序来保存的。当遍历LinkedHashSet集合里的元素时,LinkedHashSet将会按元素的添加顺序来访问集合里的元素。但是由于要维护元素的插入顺序,在性能上略低与HashSet,但在迭代访问Set里的全部元素时有很好的性能。
注意:LinkedHashSet依然不允许元素重复,判断重复标准与HashSet一致。
TreeSet
TreeSet是SortedSet接口的实现类,正如SortedSet名字所暗示的,TreeSet可以确保集合元素处于排序状态。此外,TreeSet还提供了几个额外的方法。
TreeSet是非线程安全的
方法
- comparator():返回对此 set 中的元素进行排序的比较器;如果此 set 使用其元素的自然顺序,则返回null。
- first():返回此 set 中当前第一个(最低)元素。
- last(): 返回此 set 中当前最后一个(最高)元素。
- lower(E e):返回此 set 中严格小于给定元素的最大元素;如果不存在这样的元素,则返回 null。
- higher(E e):返回此 set 中严格大于给定元素的最小元素;如果不存在这样的元素,则返回 null。
- subSet(E fromElement, E toElement):返回此 set 的部分视图,其元素从 fromElement(包括)到 toElement(不包括)。
- headSet(E toElement):返回此 set 的部分视图,其元素小于toElement。
- tailSet(E fromElement):返回此 set 的部分视图,其元素大于等于 fromElement。
排序方式
默认情况下是自然排序
自然排序
在讲自然排序之前,要先讲一下Comparable接口。
Java提供了一个Comparable接口,该接口里定义了一个compareTo(Object obj)方法,该方法返回一个整数值,实现该接口的类必须实现该方法,实现了该接口的类的对象就可以比较大小了。当一个对象调用该方法与另一个对象比较时,例如obj1.compareTo(obj2),如果该方法返回0,则表明两个对象相等;如果该方法返回一个整数,则表明obj1大于obj2;如果该方法返回一个负整数,则表明oj1小于obj2。
TreeSet会调用集合中元素所属类的compareTo(Object obj)方法来比较元素之间的大小关系,然后将集合元素按升序排列,即把通过compareTo(Object obj)方法比较后比较大的的往后排。这种方式就是自然排序。
判断元素是否相等
对于TreeSet集合而言,判断两个对象是否相等的唯一标准是:两个对象通过compareTo(Object obj)方法比较是否返回0——如果通过compareTo(Object obj)方法比较返回0,TreeSet则会认为它们相等,不予添加入集合内;否则就认为它们不相等,添加到集合内。
TreeSet是根据红黑树结构找到集合元素的存储位置。
定制排序
TreeSet的自然排序是根据集合元素中compareTo(Object obj)比较的大小,以升序排列。而定制排序是通过Comparator接口的帮助。该接口包含一个int compare(T o1,T o2)方法,该方法用于比较o1,o2的大小:如果该方法返回正整数,则表明o1大于o2;如果该方法返回0,则表明o1等于o2;如果该方法返回负整数,则表明o1小于o2。
如果要实现定制排序,则需要在创建TreeSet时,调用一个带参构造器,传入Comparator对象。并有该Comparator对象负责集合元素的排序逻辑,集合元素可以不必实现Comparable接口。
代码测试:
简单的一个学生的实体类
package com.example.demo;
import lombok.Data;
@Data
public class student
{
private String name;
private int age;
private String className;
}
测试代码
package com.example.demo;
import java.util.*;
public class demo {
public static void main(String[] args) {
student student1 = new student();
student1.setAge(14);
student1.setName("小明");
student student2 = new student();
student2.setAge(18);
student2.setName("小红");
Comparator<student> comparator = new Comparator<student>() {
@Override
public int compare(student o1, student o2) {
if(o1.getAge()<o2.getAge())
{
return 1;
}else if(o1.getAge()>o2.getAge()){
return -1;
}else{
return 0;
}
}
};
TreeSet<student> studentTreeSet = new TreeSet<>(comparator);
studentTreeSet.add(student1);
studentTreeSet.add(student2);
System.out.println(studentTreeSet);
}
}
从上面这段代码可以测试出来,当你想要升序排列的时候就判断 1小于2返回-1 就可以,但是如果你想要降序,就需要 判断1小于2 返回1了。
还有一个问题:
测试代码:
package com.example.demo;
import com.sun.xml.internal.ws.policy.privateutil.PolicyUtils;
import java.util.*;
public class demo {
public static void main(String[] args) {
student student1 = new student();
student1.setAge(14);
student1.setName("小明");
student student2 = new student();
student2.setAge(18);
student2.setName("小红");
student student3 = new student();
student3.setName("李刚");
student3.setAge(33);
Comparator<student> comparator = new Comparator<student>() {
@Override
public int compare(student o1, student o2) {
if(o1.getAge()<o2.getAge())
{
return 1;
}else if(o1.getAge()>o2.getAge()){
return -1;
}else{
return 0;
}
}
};
TreeSet<student> studentTreeSet = new TreeSet<>(comparator);
studentTreeSet.add(student1);
studentTreeSet.add(student2);
studentTreeSet.add(student3);
System.out.println("第一次排序");
System.out.println(studentTreeSet);
student1.setAge(60);
System.out.println("修改学生1年龄为60");
System.out.println(studentTreeSet);
}
}
会发现,即使排序之后修改了元素内的年龄,但是对象是不会发生变化的,还是降序来的
EnumSet
EnumSet是一个专为枚举类设计的集合类,EnumSet中的所有元素都必须是指定枚举类型的枚举值,该枚举类型在创建EnumSet时显示或隐式地指定。EnumSet的集合元素也是有序的,EnumSet以枚举值在EnumSet类内的定义顺序来决定集合元素的顺序。