Java基础——Set、HashSet、LinkedHashSet 、TreeSet

1.Set集合概述及特点:

Set继承于Collection接口,是一个不允许出现重复元素,并且无序的集合,主要有HashSet、TreeSet、LinkedHashset等实现类。

2.Set 常用方法

package Demo;
​
import java.util.Collection;
import java.util.Iterator;
​
/**
 * @Author: King
 * @Description:人类的伟大是勇气的伟大,人类的赞歌是勇气的赞歌
 * @Creat: 2021-11-25-14:37
 */
public class Test {
    public interface Set<E> extends Collection<E> {
        //添加功能
        boolean add(E e);//如果Set中未包含此元素,则添加此元素
        boolean addAll(Collection<? extends E> c);//如果 et 中没有指定collection中的所有元素,则将其添加到此set中
        //删除功能
        boolean remove(Object o);// 如果Set中包含指定元素,则将其移除
        boolean removeAll(Collection<?> c);//移除Set中与指定collection重复的元素
        void clear();// 移除此 set 中的所有元素
        //长度功能
        int size();//返回Set中的元素数
        //判断功能
        boolean isEmpty();//判断Set是否为空(包含元素),如果Set不包含元素,返回true
        boolean contains(Object o);//如果Set中包含指定元素,则返回true
        boolean containsAll(Collection<?> c);//如果此 set 包含指定collection的所有元素,则返回true。
        boolean retainAll(Collection<?> c);//仅保留Set中与指定collection重复的元素
        //获取Set集合的迭代器:
        Iterator<E> iterator();
        //把集合转换成数组
        Object[] toArray();//返回一个包含Set中所有元素的数组
        <T> T[] toArray(T[] a);//返回一个包含此 set 中所有元素的数组;返回数组的运行时类型是指定数组的类型。
    }
}

3.HsahSet

a:HashSet的特点:
    不允许出现重复因素;
    允许插入Null值;
    元素无序(添加顺序和遍历顺序不一致);
    线程不安全,若2个线程同时操作HashSet,必须通过代码实现同步
    
b:HashSet如何保证元素的唯一性
    当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据 hashCode 值决定该对象在 HashSet 中的存储位置。
HashSet 集合判断两个元素相等的标准:
两个对象通过 hashCode() 方法比较相等,并且两个对象的 equals() 方法返回值也相等。
​
结论:HashSet 保证元素唯一性是靠元素重写hashCode()和equals()方法来保证的,如果不重写则无法保证。

3.1 HashSet保证元素唯一性图解

3.2 HashSet保证元素唯一性

package Demo;
import java.util.HashSet;
import java.util.Iterator;
import java.util.function.Consumer;

/**
 * @Author: King
 * @Description:人类的伟大是勇气的伟大,人类的赞歌是勇气的赞歌
 * @Creat: 2021-11-25-15:32
 */
public class MyTest {
    public static void main(String[] args) {
        //创建HashSet集合
        HashSet<Student> hashSet = new HashSet<>();
        System.out.println("HashSet集合初始长度"+hashSet.size());
        //添加元素
        hashSet.add(new Student("张三", 17));
        hashSet.add(new Student("张三", 18));
        hashSet.add(new Student("张三", 17));
        hashSet.add(new Student("李四", 21));
        hashSet.add(new Student("王五", 19));
        hashSet.add(new Student("赵六", 18));
        //遍历集合元素
        //增强for循环
        for (Object a : hashSet) {
            System.out.println(a);
        }
        System.out.println("===================================================");
        //迭代器遍历+0
        Iterator<Student> iterator = hashSet.iterator();
        while (iterator.hasNext()){
            Student str=iterator.next();
            System.out.println(str);
        }
        System.out.println("======================================================");
        //forEach方法
        hashSet.forEach(new Consumer<Student>() {
            @Override
            public void accept(Student student) {
                System.out.println(student);
            }
        });
    }
}

未重写hashCode()和equals()方法时,元素并未唯一,运行结果如下:

Student{name='张三', age=17}
Student{name='王五', age=19}
Student{name='张三', age=18}
Student{name='张三', age=17}
Student{name='李四', age=21}
Student{name='赵六', age=18}

 储存的对象需要重写hashCode()和equals()方法

  @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);
      
    }

运行结果如下:

Student{name='王五', age=19}
Student{name='张三', age=18}
Student{name='张三', age=17}
Student{name='李四', age=21}
Student{name='赵六', age=18}

4 LinkedHashSet

数据结构:由链表和哈希表组成
•链表保证有序 哈希表保证元素唯一
•LinkedHashSet: 元素有序(存取顺序一致) , 并且唯一

4.1 LinkedHash 案例演示

package Demo;
import java.util.LinkedHashSet;
​
/**
 * @Author: King
 * @Description:人类的伟大是勇气的伟大,人类的赞歌是勇气的赞歌
 * @Creat: 2021-11-28-16:13
 */
public class MyTest1 {
    public static void main(String[] args) {
        LinkedHashSet<Integer> set = new LinkedHashSet<>();
        set.add(1);
        set.add(1);
        set.add(1);
        set.add(20);
        set.add(3);
        set.add(9);
        set.add(10);
        set.add(12);
        for (Integer s : set) {
            System.out.print(s+"\t");
        }
    }
}

运行结果:

1   20  3   9   10  12  

5 TreeSet

TreeSet: 底层数据结构是二叉数,元素唯一,且能对元素进行排序
排序:
        自然排序
        比较器排序
    到底使用的是哪一种的排序取决于,构造方法.
注意:使用TreeSet集合进行元素的自然排序,那么对元素有要求,要求这个元素
      必须实现Comparable接口 否则无法进行自然排序
 保证元素的唯一性是靠compareTo方法的返回值来确定如果返回0 表示两个元素相等则不重复存储
​

5.1 TreeSet保证元素唯一和自然排序的原理和图解

 

5.2 二叉树存储数据保证唯一性的图

二叉树的数据结构 先存入一个树根 分两个叉 存储元素时 跟树根比较 小的放在左边 大的放在右边 如果相等就不存储 取的时候按照 左中右的顺序来取

 

5.3 自然排序案例演示

注意自然排序 此对象 必须实现Comparable接口 否则报错

TreeSet存储自定义对象并遍历练习

package Demo;
import java.util.TreeSet;
​
/**
 * @Author: King
 * @Description:人类的伟大是勇气的伟大,人类的赞歌是勇气的赞歌
 * @Creat: 2021-11-28-16:38
 */
public class MyTest2 {
    public static void main(String[] args) {
        TreeSet<Student1> s1 = new TreeSet<>();
        s1.add(new Student1("张三", 18));
        s1.add(new Student1("张三", 18));
        s1.add(new Student1("张三", 17));
        s1.add(new Student1("李四", 18));
        s1.add(new Student1("王五", 19));
        s1.add(new Student1("赵六", 21));
        for (Student1 student1 : s1) {
            System.out.println(student1);
        }
    }
}

自定义Student1类,实现Comparable接口并重写compareTo方法

package Demo;
​
/**
 * @Author: King
 * @Description:人类的伟大是勇气的伟大,人类的赞歌是勇气的赞歌
 * @Creat: 2021-11-28-16:49
 */
public class Student1 implements Comparable<Student1> {
    private String name;
    private int age;
    public Student1(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student1{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    @Override
    public int compareTo(Student1 s) {
        //按年龄大小排序
        int num=this.age-s.age;
        //年龄相同,还得比较姓名是否相同
        int num1=num==0?this.name.compareTo(s.name):num;
        return num1;
    }
}

5.4 比较器排序案例演示

package Demo;
import java.util.Comparator;
import java.util.TreeSet;
​
/**
 * @Author: King
 * @Description:人类的伟大是勇气的伟大,人类的赞歌是勇气的赞歌
 * @Creat: 2021-11-28-17:07
 */
public class MyTest3 {
    public static void main(String[] args) {
        TreeSet<Student> treeSet= new TreeSet<>(new Comparator<Student>() {
            @Override
            public int compare(Student a, Student b) {
                int num=a.getAge()-b.getAge();
                int num1=num==0?a.getName().compareTo(b.getName()):num;
                return num1;
            }
        });
        treeSet.add(new Student("张三", 18));
        treeSet.add(new Student("张三", 18));
        treeSet.add(new Student("张三", 17));
        treeSet.add(new Student("李四", 18));
        treeSet.add(new Student("王五", 19));
        treeSet.add(new Student("赵六", 21));
        for (Student student : treeSet) {
            System.out.println(student);
        }
    }
}

6 练习

案例1:

案例演示
    需求:编写一个程序,获取10个1至20的随机数,要求随机数不能重复, 并把最终的随机数输出到控制台。
​
分析:
    a: 定义一个集合(  选HashSet 可以不重复;选TreeSet 不重复还可以排序)
    b: 产生随机数,把随机数添加到集合中
    c: 判断集合的长度,使用while循环实现
package Demo;
​
import java.util.Random;
import java.util.TreeSet;
import java.util.function.Consumer;
​
/**
 * @Author: King
 * @Description:人类的伟大是勇气的伟大,人类的赞歌是勇气的赞歌
 * @Creat: 2021-11-28-17:17
 */
public class MyTest4 {
    public static void main(String[] args) {
        Random random = new Random();
        TreeSet<Integer> integers = new TreeSet<>();
        while (integers.size()<10){
            integers.add(random.nextInt(20)+1);
        }
        integers.forEach(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) {
                System.out.print(integer+"\t");
            }
        });
    }
}

案例2:

A:案例演示: 需求:键盘录入3个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台。
/**
     * 步骤: 
     *      a: 自定义一个学生类
     *      b: 创建一个TreeSet集合对象(使用比较器进行排序)
     *      c: 键盘录入学生的数据,然后把学生的数据封装成一个学生对象,把学生对象添加到集合中
     *      d: 遍历集合
     */

TreeSet存储自定义对象并遍历

import java.util.Comparator;
import java.util.Scanner;
import java.util.TreeSet;
​
/**
 * @Author: King
 * @Description:人类的伟大是勇气的伟大,人类的赞歌是勇气的赞歌
 * @Creat: 2021-11-23-15:11
 */
public class Test5 {
    public static void main(String[] args) {
        TreeSet<Student1> s1 = new TreeSet<>(new Comparator<Student1>() {
            @Override
            public int compare(Student1 a, Student1 b) {
                int num=a.Sum()-b.Sum();
                int num1=num==0?a.getName().compareTo(b.getName()):num;
                return num1;
            }
        });
        for (int i = 1; i < 4; i++) {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入第" + i + "个学生姓名");
            String name = sc.nextLine();
            Scanner sc1 = new Scanner(System.in);
            System.out.println("请输入"+name + "的语文成绩" );
            int chinese = sc.nextInt();
            Scanner sc2 = new Scanner(System.in);
            System.out.println("请输入" + name + "的数学成绩");
            int math = sc.nextInt();
            Scanner sc3 = new Scanner(System.in);
            System.out.println("请输入" + name + "的英语成绩");
            int english = sc.nextInt();
            s1.add(new Student1(name,chinese,math,english));
        }
​
        System.out.print("排名\t"+"姓名\t" + "语文\t" + "数学\t" + "英语\t" + "总分");
        System.out.println();
        for (Student1 student : s1) {
            System.out.println(student);
    }
}
}

定义一个Student1类

/**
 * @Author: King
 * @Description:人类的伟大是勇气的伟大,人类的赞歌是勇气的赞歌
 * @Creat: 2021-11-23-15:16
 */
public class Student1 {
    private String name;//姓名
    private int chinese;//语文成绩
    private int math;//数学成绩
    private int english;//英语成绩
    private static int rank=1;//排名
    public Student1() {
​
    }
    public Student1(String name, int chinese,int math,int english) {
        this.name=name;
        this.chinese=chinese;
        this.math=math;
        this.english=english;
    }
   //总分
    public int Sum(){
      return math+chinese+english;
    }
    public String getName(){
        return name;
    }
    public void setName(String name){
        this.name=name;
    }
    @Override
    public String toString() {
        return rank+++"\t"+name+"\t"+chinese+"\t"+math+"\t"+english +"\t"+Sum();
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值