Set集合

  在Collection集合中List集合中的元素有序且允许重复,而Set集合中元素是唯一的,下面为大家介绍几种Set集合。

1、HashSet集合

  HashSet集合中元素的存取是无序的,且元素是唯一的。它的底层数据结构是哈希表,具有链表和数组的特点。
  HashSet集合靠着重写 hashCode() 和 equals() 方法来实现元素的唯一,如果不重写则不能保证元素的唯一性。

public class SetDemo {
    public static void main(String[] args) {
        HashSet<String> set = new HashSet<>();
        set.add("小明");
        set.add("小明");
        set.add("小红");
        set.add("小红");
        set.add("小李");
        set.add("小李");
        for (String s : set) {
            System.out.println(s);
        }
    }
}

//运行结果为:
小明
小李
小红

  由上面的代码可见,当元素重复存储的时候,在输出的时候元素就只有一个,重复的元素没有被存储(因为String类中已经重写过了方法)。如果我们存储的是自定义类的时候需要我们手动重写 hashCode() 和 equals() 方法来保证元素的唯一性。但是在重写的时候我们需要合理的进行重写,尽量减少碰撞。代码实现如下:
Student类

import java.util.Objects;
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 String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", 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);
    }
}

Test类

import java.util.HashSet;
public class MyTest {
    public static void main(String[] args) {
        Student s1 = new Student("王五", 25);
        Student s2 = new Student("王五", 25);
        Student s3 = new Student("王五", 25);
        Student s4 = new Student("王五", 252);
        Student s5 = new Student("王五2", 235);
        Student s6 = new Student("王五3", 25);
        Student s7 = new Student("王五4", 2665);
        Student s8 = new Student("王五5", 285);
        Student s9 = new Student("王五6", 285);
        Student s10 = new Student("王五7", 255);
        HashSet<Student> hashSet = new HashSet<>();
        hashSet.add(s1);
        hashSet.add(s2);
        hashSet.add(s3);
        hashSet.add(s4);
        hashSet.add(s5);
        hashSet.add(s6);
        hashSet.add(s7);
        hashSet.add(s8);
        hashSet.add(s9);
        hashSet.add(s10);
        for (Student student : hashSet) {
            System.out.println(student.getName() + "==" + student.getAge());
        }
    }
}

  上面的测试类的代码中HashSet集合中存储的为学生类,如果不手动重写 hashCode() 和 equals() 方法那么就无法保证元素的唯一。

2、LinkedHashSet集合

  LinkedHashSet集合元素有序并且元素唯一,因为它的底层数据结构是链表和哈希表,链表可以保证元素唯一,哈希表可以保证元素的唯一。

import java.util.LinkedHashSet;
public class MyTest {
    public static void main(String[] args) {
        LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
        linkedHashSet.add("爱");
        linkedHashSet.add("你");
        linkedHashSet.add("三");
        linkedHashSet.add("千");
        linkedHashSet.add("遍");
        linkedHashSet.add("三");
        linkedHashSet.add("千");
        linkedHashSet.add("遍");
        linkedHashSet.add("爱");
        for (String s : linkedHashSet) {
            System.out.println(s);
        }
    }
}
//运行结果为
爱你三千遍

  从运行结果可以看出,遍历的时候输出的顺序和存储的顺序相同,而后面重复的元素也没有重复存储。

3、TreeSet集合

  TreeSet集合的特点就是可以对集合进行排序,因为它的底层数据结果为二叉树。排序有两种方法,一种为自然排序,另一种为比较器排序。下面为大家简单来介绍一下这两种排序的方法。

a、自然排序

  当存储的元素为基本数据类型的时候,存储的时候就进行排序,当我们遍历的时候已经排好顺序了。举例说明

public class MyTest {
    public static void main(String[] args) {
        TreeSet<String> treeSet = new TreeSet<>();
        TreeSet<Integer> treeSet2 = new TreeSet<>();
        treeSet.add("a");
        treeSet.add("a");
        treeSet.add("b");
        treeSet.add("d");
        treeSet.add("c");
        treeSet2.add(24);
        treeSet2.add(19);
        treeSet2.add(18);
        treeSet2.add(24);
        for (String string : treeSet) {
            System.out.println(string);
        }
        System.out.println("------------");
        for (Integer integer : treeSet2) {
            System.out.println(integer);
        }
    }
}

运行结果如下图所示
在这里插入图片描述
  由代码看出,元素在遍历的时候已经排好了顺序。


  当我们存储的为自定义类的元素时,我们需要这个自定义类实现 Comparable 接口重写里面的 comPareTo 方法,根据此方法的返回值的正负和0 来决定元素在二叉树的位置。下面让我们定义一个Student类,并对其进行测试。

public class Student implements Comparable<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 String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public int compareTo(Student s) {
        //比较逻辑是按照年龄大小来排序
        int num = this.age - s.age;
        //当年龄相同不能说明他是同一个对象,还得比较姓名
        int num2 = num == 0 ? this.name.compareTo(s.name) : num;
        return num2;
    }
}
import java.util.TreeSet;

/**
 * @Author: Administrator
 * @CreateTime: 2019-05-11 10:31
 */
public class MyTest {
    public static void main(String[] args) {
        //按照学生的年龄大小来排序
        Student s1 = new Student("王五", 21);
        Student s11 = new Student("王五", 21);
        Student s123 = new Student("李四", 21);
        Student s2 = new Student("王五", 22);
        Student s3 = new Student("王五111", 25);
        Student s4 = new Student("王五123", 252);
        Student s5 = new Student("王五2222", 235);
        Student s6 = new Student("王五3", 25);
        Student s7 = new Student("欧阳王五", 2665);
        Student s8 = new Student("琦玉", 288);
        Student s9 = new Student("", 285);
        Student s10 = new Student("王五7", 255);
        TreeSet<Student> treeSet = new TreeSet<>();
        treeSet.add(s1);
        treeSet.add(s11);
        treeSet.add(s2);
        treeSet.add(s3);
        treeSet.add(s4);
        treeSet.add(s5);
        treeSet.add(s6);
        treeSet.add(s7);
        treeSet.add(s8);
        treeSet.add(s9);
        treeSet.add(s10);
        treeSet.add(s123);
        for (Student student : treeSet) {
            System.out.println(student);           
        }
    }
}

代码执行结果如下图
在这里插入图片描述
  由代码执行的结果看,学生已经按照年龄排好了顺序,你想怎样排序就怎样重新compareTo方法中的逻辑。

b、比较器排序

  当使用比较器排序的时候,我们需要创建一个类来实现 Comparator 接口,然后重写里面的逻辑,然后再创建该类对象,传入到TreeSet集合中,但是不能每次我们使用比较器排序都要创建一个类,那么我们可以使用匿名对象直接传入,代码实现如下,学生类为上述学生类,测试类如下

import java.util.Comparator;
import java.util.TreeSet;
public class MyTest3 {
    public static void main(String[] args) {
        //传入一个比较器
        Comparator comparator = new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
                //按照姓名长度来拍
                int num = s1.getName().length() - s2.getName().length();
                int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
                int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
                return num3;
            }
        };

        TreeSet<Student> treeSet = new TreeSet<>(comparator);
         treeSet.add(new Student("李", 21));
        treeSet.add(new Student("李十八", 212));
        treeSet.add(new Student("欧阳", 241));
        treeSet.add(new Student("王也", 2771));
        treeSet.add(new Student("王也也", 21733));
        treeSet.add(new Student("王也也", 21733));
        treeSet.add(new Student("王也也", 21337));
        treeSet.add(new Student("王也也", 217));
        treeSet.add(new Student("王也也", 217));
        for (Student student : treeSet) {
            System.out.println(student);
        }
    }
}

运行结果如下图

在这里插入图片描述
  上面的代码是通过传入一个比较器来进行排序的,通过匿名对象传入了一个比较器然后重写compare()方法来确定元素在二叉树中的位置。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值