流殃的博客

| Comments

HashSet

HashSet是Set接口的典型实现,实现了Set接口中的所有方法,并没有添加额外的方法,大多数时候使用Set集合时就是使用这个实现类。HashSet按Hash算法来存储集合中的元素。因此具有很好的存取和查找性能。

特点

  1. 不能保证元素的排列顺序,顺序可能与添加顺序不同,顺序也有可能发生变化。
  2. HashSet不是同步的,如果多个线程同时访问一个HashSet,则必须通过代码来保证其同步。
  3. 集合元素值可以是null。
  4. 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);

    }
}

image.png
从上面这段代码可以测试出来,当你想要升序排列的时候就判断 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);

    }
}

image.png
会发现,即使排序之后修改了元素内的年龄,但是对象是不会发生变化的,还是降序来的

EnumSet

EnumSet是一个专为枚举类设计的集合类,EnumSet中的所有元素都必须是指定枚举类型的枚举值,该枚举类型在创建EnumSet时显示或隐式地指定。EnumSet的集合元素也是有序的,EnumSet以枚举值在EnumSet类内的定义顺序来决定集合元素的顺序。

参考

Comments

评论