Java集合3_HashSet

1 HashSet集合

1.1 HashSet存储字符串并遍历

* A:Set集合概述及特点

* Set集合,无索引,不可以重复,无序(存取不一致)

* B:案例演示

* HashSet存储字符串并遍历

package com.jhedu.day17;
import java.util.ArrayList;
import java.util.HashSet;
public class Demo1_HashSet {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        //boolean b = list.add("d");
        /**
         * 1. 在我们使用list集合的时候,add方法永远返回的是ture 有序,有索引
         * 2. 在使用set集合的时候,add方法在添加重复元素时返回的是false 无序,无索引
         *
         */
        HashSet<String> hashSet = new HashSet<>();
        boolean b = hashSet.add("wa");
        hashSet.add("zf");
        hashSet.add("qw");
        hashSet.add("c");
        hashSet.add("b");
        hashSet.add("d");
        hashSet.add("e");
        hashSet.add("f");
        System.out.println(hashSet.size());   
        System.out.println(hashSet);
        // 增强for循环遍历Hashset
        for(String s : hashSet){
            System.out.println(s);
        }
    }
}

1.1 HashSet存储自定义对象保证元素唯一性

一个类想拥有哪些特点,是有他的功能决定的。

* A:案例演示

* 存储自定义对象,并保证元素唯一性。

* 重写hashCode()和equals()方法

 

public static void demo2() {
    // HashSet存储自定义对象——学生类
    /**
     * 当使用HashSet存储自定义对象时,必须重写equals方法和hashCode方法才能保证元素的唯一
     */
    HashSet<Student> hashSet = new HashSet<>();
    hashSet.add(new Student("A",13));     // 1
    hashSet.add(new Student("A",13));     // 2   A.equals(A);
    hashSet.add(new Student("B",36));
    hashSet.add(new Student("C",31));
    hashSet.add(new Student("D",23));
    hashSet.add(new Student("C",34));
    hashSet.add(new Student("C",34));
    System.out.println(hashSet.size());   // 
    for(Student s : hashSet){
        System.out.print(s + " ");
    }
}

 

1.1 HashSet如何保证元素唯一性的原理

* A:画图演示

* 画图说明比较过程

把对象往集合中添加的时候,会调用hashcode方法Hashcode值一样的时候才调用equals方法。要节约代码就让返回的hashCode尽量不同

 

* B:代码优化

* 为了减少比较,优化hashCode()代码写法。

* 最终版就是自动生成即可。

package com.jhedu.day17;
import com.sun.xml.internal.ws.encoding.HasEncoding;
import java.util.ArrayList;
import java.util.HashSet;
public class Demo1_HashSet {
    public static void main(String[] args) {
        demo2();
    }
    public static void demo2() {
        // HashSet存储自定义对象——学生类
        /**
         * 当使用HashSet存储自定义对象时,必须重写equals方法和hashCode方法才能保证元素的唯一
         */
        HashSet<Student> hashSet = new HashSet<>();
        // hashCode执行的时间就是向集合中添加元素的时候
        // equals方法执行的时间是只有hashCode值一样的时候,equals方法才会执行
        // 当HashSet存储自定义对象时,必须重写equals方法和hashCode方法,才能保证元素唯一
        hashSet.add(new Student("A",13));     // 1
        hashSet.add(new Student("A",13));     // 2   A.equals(A);
        hashSet.add(new Student("A",13));
        hashSet.add(new Student("A",13));
        System.out.println(hashSet.size());   // 7 5
        for(Student s : hashSet){
            System.out.print(s + " ");
        }
    }
    public static void demo() {
        //boolean b = list.add("d");
        /**
         * 1. 在我们使用list集合的时候,add方法永远返回的是ture 有序,有索引
         * 2. 在使用set集合的时候,add方法在添加重复元素时返回的是false 无序,无索引
         */
        HashSet<String> hashSet = new HashSet<>();
        boolean b = hashSet.add("wa");
        hashSet.add("zf");
        hashSet.add("qw");
        hashSet.add("c");
        hashSet.add("b");
        hashSet.add("d");
        hashSet.add("e");
        hashSet.add("f");

        System.out.println(hashSet.size());   // 7 4
        System.out.println(hashSet);

        // 增强for循环遍历Hashset
        for(String s : hashSet){
            System.out.println(s);
        }
    }
}

* 1.HashSet原理

* 我们使用Set集合都是需要去掉重复元素的, 如果在存储的时候逐个equals()比较, 效率较低,哈希算法提高了去重复的效率, 降低了使用equals()方法的次数

* 当HashSet调用add()方法存储对象的时候, 先调用对象的hashCode()方法得到一个哈希值, 然后在集合中查找是否有哈希值相同的对象

* 如果没有哈希值相同的对象就直接存入集合

* 如果有哈希值相同的对象, 就和哈希值相同的对象逐个进行equals()比较,比较结果为false就存入, true则不存

* 2.将自定义类(如,StudentPerson,Cat)的对象存入HashSet去重复

* 类中必须重写hashCode()和equals()方法

* hashCode(): 属性相同的对象返回值必须相同, 属性不同的返回值尽量不同(提高效率)

* equals(): 属性相同返回true, 属性不同返回false,返回false的时候存储

 

1.1 LinkedHashSet的概述和使用

* A:LinkedHashSet的特点

  是唯一能保证怎么存就怎么取的set集合

* B:案例演示

* LinkedHashSet的特点

* 可以保证怎么存就怎么取 

package com.jhedu.day17;
import java.util.LinkedHashSet;
public class Demo2_LinkedHashSet {
    public static void main(String[] args) {
        LinkedHashSet<String> linkSet = new LinkedHashSet<>();
        /* LinkedHashSet可以保证元素唯一,并且可以保证有序(怎么存,就怎么取) */
        linkSet.add("f");
        linkSet.add("a");
        linkSet.add("b");
        linkSet.add("c");
        linkSet.add("c");
        linkSet.add("d");
        linkSet.add("e");
        // 增强for循环遍历LinkedHashSet
        for(String s :linkSet){
            System.out.print(s + " ");
        }
    }
}

2 TreeSet集合

2.1 TreeSet存储Integer类型的元素并遍历

* A:案例演示

* TreeSet存储Integer类型的元素并遍历

  TreeSet集合是用来对元素进行排序的,同样他也可以保证元素的唯一

public static void demo() {
    /**
     * TreeSet会保证元素的唯一,并且会对元素进行排序
     */
    TreeSet<Integer> treeSet = new TreeSet<>();
    treeSet.add(15);
    treeSet.add(56);
    treeSet.add(28);
    treeSet.add(16);
    treeSet.add(66);
    treeSet.add(1);
    treeSet.add(1);
    treeSet.add(66);
    treeSet.add(100);
    treeSet.add(0);
    System.out.println(treeSet.size());
    System.out.println(treeSet);
}

 

2.2 TreeSet存储自定义对象(CompareTo方法)重点和难点

 

package com.jhedu.day17;
import java.util.TreeSet;
public class Demo4_TreeSet {
    public static void main(String[] args) {
        demo2();
    }
    public static void demo2() {
        String s1 = "b";
        String s2 = "a";
        s2.compareTo(s1);
        /**
         * 当两个对象相等时返回0
         * 当调用对象小于被调用对象时,返回负数
         * 当调用对象大于被调用对象时,返回正数
         *
         * TreeSet存储对象的依据只会依赖与compareTo方法返回值。
         */
        // System.out.println(s2.compareTo(s1));  // 代表了String类重写compareTo方法

        /**
         * TreeSet中增加自定义对象时,如果没有提供可比较的方法,
         * 就会抛出ClassCastException类型转换错误异常,解决方法是必须提供compareTo方法的重写
         * 具体就实现Comparable接口。
         */
        TreeSet<Student> treeSet = new TreeSet<>();
        treeSet.add(new Student("张三",23));
        treeSet.add(new Student("李四",34));、
        treeSet.add(new Student("周七",23));
        treeSet.add(new Student("王五",56));
        treeSet.add(new Student("赵六",18));
        treeSet.add(new Student("张三",23));
        //System.out.println(treeSet.size());
        for(Student s: treeSet){
            System.out.println(s);
        }
    }
}

 

package com.se.bean;

import java.util.Objects;

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

    @Override
    public int compareTo(Student o) {
//        int num = this.age - o.age;
//        return num==0?this.age-o.age:num;
        int num1 = this.name.compareTo(o.name); // name进行比较,返回int类型,0,1,-1
        return num1 == 0 ? this.age - o.age : num1; // 如果名字相等返回0,再进行年龄比较,否则返回num1
    }
}

2.6 TreeSet原理

* 1.特点

* TreeSet是用来排序的, 可以指定一个顺序, 对象存入之后会按照指定的顺序排列

* 2.使用方式

* a.自然顺序(Comparable)

* TreeSet类的add()方法中会把存入的对象提升为Comparable类型

* 调用对象的compareTo()方法和集合中的对象比较

* 根据compareTo()方法返回的结果进行存储

* b.比较器顺序(Comparator)

* 创建TreeSet的时候可以制定 一个Comparator

* 如果传入了Comparator的子类对象, 那么TreeSet就会按照比较器中的顺序排序

* add()方法内部会自动调用Comparator接口中compare()方法排序

* 调用的对象是compare方法的第一个参数,集合中的对象是compare方法的第二个参数

* c.两种方式的区别

* TreeSet构造函数什么都不传, 默认按照类中Comparable的顺序(没有就报错ClassCastException)

* TreeSet如果传入Comparator, 就优先按照Comparator

 

2.7 作业

 

2.7.1从键盘接收一个字符串, 程序对其中所有字符进行排序

 

例如键盘输入: helloitcast程序打印:acehillostt

 

package net.jhedu.fiften;
import java.util.Comparator;
import java.util.Scanner;
import java.util.TreeSet;
public class Demo1_HomeWorkF {
    /**
     * 从键盘接收一个字符串, 程序对其中所有字符进行排序,例如键盘输入: helloitcast程序打印:acehillostt
     * 分析:
     * 1,键盘录入字符串,Scanner
     * 2,将字符串转换为字符数组
     * 3,定义TreeSet集合,传入比较器对字符排序并保留重复
     * 4,遍历字符数组,将每一个字符存储在TreeSet集合中
     * 5,遍历TreeSet集合,打印每一个字符
     */
    public static void main(String[] args) {
        //1,键盘录入字符串,Scanner
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个字符串");
        String line = sc.nextLine();
        //2,将字符串转换为字符数组
        char[] arr = line.toCharArray();
        //3,定义TreeSet集合,传入比较器对字符排序并保留重复
        TreeSet<Character> ts = new TreeSet<>(new Comparator<Character>() {

            @Override
            public int compare(Character c1, Character c2) {
                //int num = c1 - c2;            //自动拆箱
                int num = c1.compareTo(c2);
                return num == 0 ? 1 : num;//相等的时候 返回1 保留相同的。
            }
        });
        //4,遍历字符数组,将每一个字符存储在TreeSet集合中
        for(char c : arr) {
            ts.add(c); //自动装箱
        }
        //5,遍历TreeSet集合,打印每一个字符
        for(Character c : ts) {
            System.out.print(c);
        }
    }
}

 

2.7.2在一个集合中存储了无序并且重复的字符串,

定义一个方法,让其有序(字典顺序),而且还不能去除重复 

 

package com.jh.day29.set;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.TreeSet;
public class Demo04_TreeSet {
    /**
     * 在一个集合中存储了无序并且重复的字符串,定义一个方法,让其有序(字典顺序),而且还不能去除重复
     * 
     * 分析:
     * 1,定义一个List集合,并存储重复的无序的字符串
     * 2,定义方法对其排序保留重复
     * 3,打印List集合
     */
    public static void main(String[] args) {
        //1,定义一个List集合,并存储重复的无序的字符串
        ArrayList<String> list = new ArrayList<>();
        list.add("aaa");
        list.add("aaa");
        list.add("ccc");
        list.add("ddd");
        list.add("fffffffffff");
        list.add("heima");
        list.add("itcast");
        list.add("bbbb");
        list.add("aaa");
        list.add("aaa");
        //2,定义方法对其排序保留重复
        sort(list);
        // 3,打印List集合
        System.out.println(list);
    }
    /*
     * 定义方法,排序并保留重复
     * 分析:
     * 1,创建TreeSet集合对象,因为String本身就具备比较功能,但是重复不会保留,所以我们用比较器
     * 2,将list集合中所有的元素添加到TrreSet集合中,对其排序,保留重复
     * 3,清空list集合
     * 4,将TreeSet集合中排好序的元素添加到list中
     */
    public static void sort(List<String> list) {
        //1,创建TreeSet集合对象,因为String本身就具备比较功能,但是重复不会保留,所以我们用比较器
        TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {

            @Override
            public int compare(String s1, String s2) {
                int num = s1.compareTo(s2);                    //比较内容为主要条件
                return num == 0 ? 1 : num;                    //保留重复
            }
        });
        //2,将list集合中所有的元素添加到TrreSet集合中,对其排序,保留重复
        ts.addAll(list);
        //3,清空list集合
        list.clear();
        //4,将TreeSet集合中排好序的元素添加到list中
        list.addAll(ts);
    }
}

 

2.7.3键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台

/**

 * * A:案例演示

 * 需求:键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台。

 *

 * 分析:

 * 1,定义一个学生类

 * 成员变量:姓名,语文成绩,数学成绩,英语成绩,总成绩

 * 成员方法:空参,有参构造,有参构造的参数分别是姓名,语文成绩,数学成绩,英语成绩

 * toString方法,在遍历集合中的Student对象打印对象引用的时候会显示属性值

 * 2,键盘录入需要Scanner,创建键盘录入对象

 * 3,创建TreeSet集合对象,在TreeSet的构造函数中传入比较器,按照总分比较

 * 4,录入五个学生,所以以集合中的学生个数为判断条件,如果size是小于5就进行存储

 * 5,将录入的字符串切割,用逗号切割,会返回一个字符串数组,将字符串数组中从二个元素转换成int数,

 * 6,将转换后的结果封装成Student对象,将Student添加到TreeSet集合中

 * 7,遍历TreeSet集合打印每一个Student对象

 */

 

package com.jh.day29.bean;

public class Student {
    private String name;
    private int chinese;
    private int math;
    private int english;
    private int sum;
    public Student() {
        super();
    }
    public Student(String name, int chinese, int math, int english) {
        super();
        this.name = name;
        this.chinese = chinese;
        this.math = math;
        this.english = english;
        this.sum = this.chinese + this.math + this.english;
    }
    public int getSum() {
        return sum;
    }
    public String toString() {
        return name + "," + chinese + "," + math + "," + english + "," + sum;
    }
}
public static void main(String[] args) {
        //2,键盘录入需要Scanner,创建键盘录入对象
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入学生成绩格式是:姓名,语文成绩,数学成绩,英语成绩");
        //3,创建TreeSet集合对象,在TreeSet的构造函数中传入比较器,按照总分比较
        TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {

            @Override
            public int compare(Student s1, Student s2) {
                int num = s2.getSum() - s1.getSum();
                return num == 0 ? 1 : num;
            }
        });
        //4,录入五个学生,所以以集合中的学生个数为判断条件,如果size是小于5就进行存储
        while(ts.size() < 5) {
            //5,将录入的字符串切割,用逗号切割,会返回一个字符串数组,将字符串数组中从二个元素转换成int数,
            String line = sc.nextLine();
            String[] arr = line.split(",");
            int chinese = Integer.parseInt(arr[1]);
            int math = Integer.parseInt(arr[2]);
            int english = Integer.parseInt(arr[3]);
            //6,将转换后的结果封装成Student对象,将Student添加到TreeSet集合中
            ts.add(new Student(arr[0], chinese, math, english));
        }
        
        //7,遍历TreeSet集合打印每一个Student对象
        System.out.println("排序后的学生信息:");
        for (Student s : ts) {
            System.out.println(s);
        }
    }

 

 

posted @ 2021-07-16 17:28  蔡地像徐坤  阅读(169)  评论(0)    收藏  举报