• 【Java的集合框架之set 28】


    一、Set集合

    元素不可以重复,并且是无序的(也就是说不保证排序)

    Set集合的方法和Collection方法一样,拿来直接用就行

    二、常用的两个子类对象

    |-- HashSet  内部数据结构是哈希表,是不同步的  -->实现排序是通过hashCode  和 equals进行比较

    |-- TreeSet   按照元素字典顺序排序的,是不同步的 

      -->实现排序的方法一:让元素自身具备比较功能,也就是需要实现comparable接口,覆盖compareTo方法

         判断元素唯一性的方法:就是根据比较方法的返回结果是否是0 ,是0 就不存

         -->实现排序的方法二:如果对象中不具备自然排序或者是对象类不能进行修改,这时候就需要让集合本身具备排序功能(定义一个类实现comparator接口,覆盖compare方法,将该类对象作为  参数传递给TheeSet集合的构造函数)

    三、详细介绍HashSet

    --------举例演示HashSet----------

    package com.JavaStudy01.Set;
    
    import java.util.HashSet;
    import java.util.Iterator;
    
    /**
     * @Author wufq
     * @Date 2020/7/31 14:39
     */
    public class HashSetDemo01 {
        public static void main(String[] args){
            HashSet  hs = new HashSet();
    
            hs.add("haha");
            hs.add("xixi");
            hs.add("hehe");
            hs.add("hehe");
            hs.add("hehe");
            hs.add("hehe");
            hs.add("heihei");
    
            Iterator it=hs.iterator();
            while (it.hasNext()){
                System.out.println(it.next());
            }
    
        }
    }
    =====执行结果====
    haha
    heihei
    xixi
    hehe

    通过执行结果证明:Set集合确实是存放不重复的对象,并且还是无序的

    1、Set集合的HashCode值

    Set集合里面放的对象其实是通过hashCode算出来的值

    哈希表:哈希是一种算法,算出来的值存储起来 就形成了哈希表

     2、HashSet存储自定义对象(要求:往HashSet集合里面存放person对象,如果姓名和年龄相同,视为同一个人。视为相同元素)

    HashSet集合数据结构是哈希表,所以存储元素的时候使用元素的hashCode方法来确定位置,如果位置相同的话在用元素的equals方法来确定是否相同

    举例说明:

    package com.JavaStudy01.Set;
    
    import com.JavaStudy01.Bean.Person;
    
    import java.util.HashSet;
    import java.util.Iterator;
    
    /**
     * @Author wufq
     * @Date 2020/7/31 16:32
     * HashSet存储自定义对象
     */
    public class HashSetDemo02 {
        public static void main(String[] args){
            HashSet hs = new HashSet();
            hs.add(new Person("lisi1",21));
            hs.add(new Person("lisi2",22));
            hs.add(new Person("lisi9",23));
            hs.add(new Person("lisi9",23));
            hs.add(new Person("lisi8",25));
            
            Iterator it=hs.iterator();
            while (it.hasNext()){
                Person p = (Person)it.next();
                System.out.println(p.getName()+"::"+p.getAge() );
            }
        }
    }
    =====执行结果=====
    lisi1::21
    lisi8::25
    lisi9::23
    lisi9::23
    lisi2::22

    通过执行结果发现,相同的姓名和年龄不是同一个元素,并且被打印出来了(不符合我们的要求)

    分析原因:

    因为person对象也是继承了Object对象,而Object类里面同样包含了hashcode方法,所以只要new了一个对象,就会有一个hashcode值,所以即使有两个hs.add(new Person("lisi9",23));
    那么也会有两个不同的hashCode值,因此会打印出来

    如何解决:

    Person类重写hashCode()方法和equals()方法

    package com.JavaStudy01.Bean;
    
    /**
     * @Author wufq
     * @Date 2020/7/31 11:24
     */
    public class Person extends Object{
        private String name;
        private int age;
    
        public Person() {
        }
    
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        @Override
        public int hashCode() {
            System.out.println(this+"........hachCode");//验证是否真的在调用hashCode方法
            return name.hashCode()+age;
        }
    
        @Override
        public boolean equals(Object obj) {
            Person p= (Person)obj;
    
            System.out.println(this+"........equals"+obj);//验证是否真的在调用equals方法
            //this表示谁去调用就是谁
            return this.name.equals(p.name)&&this.age == p.age;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public int getAge() {
            return age;
        }
    
        public String toString(){
            return name+"::"+age;
        }
    
    }

    这样在执行HashSetDemo02,结果就没有重复的内容了,并且可以看出hashSet确实是先计算hashcode的值,然后在计算equals

    ======重写equals,hashCode以后的执行结果=====

    lisi1::21........hachCode
    lisi2::22........hachCode
    lisi9::23........hachCode
    lisi9::23........hachCode
    lisi9::23........equals lisi9::23
    lisi8::25........hachCode
    lisi1::21
    lisi2::22
    lisi8::25
    lisi9::23

    ------>

    可以看出lisi9::23  确实是先判断hashcode的值,然后在判断的是equals

    -------->额外的知识点补充:<------------

     如果是存储对象,那么重写equals方法如下:

    public boolean equals(Object obj) {
            Person p= (Person)obj;
    
            if(this == obj){
                return true;
            }
            if(!(obj instanceof Person)){
                throw new ClassCastException("类型不对!");
            }
    
        }

    3、框架练习:

    ------->定义功能去除ArrayList中的重复元素

    package com.JavaStudy01.Set;
    
    import java.util.ArrayList;
    import java.util.Iterator;
    
    /**
     * @Author wufq
     * @Date 2020/8/4 17:20
     * 定义功能去除ArrayList里面的重复元素--->去除重复的字符串
     */
    public class ArrayListDemo03 {
    
    
        public static void main(String[] args){
            ArrayList al = new ArrayList();
            al.add("abc1");
            al.add("abc2");
            al.add("abc3");
            al.add("abc3");
    
            System.out.println("排重之前:"+al);
            al= getGetsingleElement(al);
            System.out.println("排重之后:"+al);
        }
    
        public static ArrayList getGetsingleElement(ArrayList al) {
            //1、定义一个临时容器
            ArrayList temp = new ArrayList();
    
            //2、迭代al集合
            Iterator it = al.iterator();
            while (it.hasNext()){
                Object obj=it.next();
                //3、判断比迭代到的元素是否在临时容器内
                if(!temp.contains(obj)){
                    temp.add(obj);
                }
            }
    
            return temp;
        }
    
    }
    ======执行结果======
    排重之前:[abc1, abc2, abc3, abc3]
    排重之后:[abc1, abc2, abc3]

    -------->定义功能去除ArrayList中的重复自定义对象(这里只需要重写person类内的equals方法)

    package com.JavaStudy01.Set;
    
    import com.JavaStudy01.Bean.Person;
    
    import java.util.ArrayList;
    import java.util.Iterator;
    
    /**
     * @Author wufq
     * @Date 2020/8/4 18:17
     * ArrayList去除重复的自定义对象
     */
    public class ArrayListDemo02 {
    
        public static void main(String[] args){
            ArrayList ali = new ArrayList();
            ali.add(new Person("lisi1",23));
            ali.add(new Person("lisi2",22));
            ali.add(new Person("lisi3",21));
            ali.add(new Person("lisi4",20));
            ali.add(new Person("lisi1",23));
    
            System.out.println(ali);
            ali = StingElement(ali);
            System.out.println(ali);
        }
    
        private static ArrayList StingElement(ArrayList ali) {
    
            ArrayList temp = new ArrayList();
    
            Iterator it = ali.iterator();
            while (it.hasNext()){
                Object obj = it.next();
                if(!temp.contains(obj)){
                    temp.add(obj);
                }
    
            }
    
            return temp;
        }
    
    }
    =======执行结果======
    [lisi1::23, lisi2::22, lisi3::21, lisi4::20, lisi1::23]
    [lisi1::23, lisi2::22, lisi3::21, lisi4::20]

    注意:hashSet集合无论是包含或者删除一个元素,就需要判断该元素是否和容器内的元素是否相同,例如:对于ArrayList这样的集合,contains、remove需要重写hashCode和equals方法。hashSet集合只需要重写equals方法

     4、HashSet是无序并且不保证重复,为了改进引进了子类LinkedHashSet(---->有序并且是唯一的)

    package com.JavaStudy01.Set;
    
    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.LinkedHashSet;
    
    
    /**
     * @Author wufq
     * @Date 2020/8/6 09:28
     */
    public class LinkedHashSet01 {
        public static void main(String[] args){
            HashSet hs = new LinkedHashSet();
    
            hs.add("haha");
            hs.add("xixi");
            hs.add("hehe");
            hs.add("hehe");
            hs.add("hehe");
            hs.add("hehe");
            hs.add("heihei");
    
            Iterator it=hs.iterator();
            while (it.hasNext()){
                System.out.println(it.next());
            }
    
        }
    }
    ====执行结果====
    haha
    xixi
    hehe
    heihei

    四、详细介绍TreeSet

    1、比较基本数据类型

    package com.JavaStudy01.Set;
    
    import java.util.Iterator;
    import java.util.TreeSet;
    
    /**
     * @Author wufq
     * @Date 2020/8/6 09:53
     */
    public class TreeSetDemo01 {
        public static void main(String[] args){
            TreeSet ts = new TreeSet();
    
            ts.add("aa");
            ts.add("abc");
            ts.add("zz");
            ts.add("hh");
    
            Iterator it = ts.iterator();
    
            while (it.hasNext()){
                System.out.println(it.next());
            }
    
        }
    
    }
    ====执行结果====
    aa
    abc
    hh
    zz

    通过执行结果发现:基本数据类型的元素按照元素字典进行排序

    2、比较自定义类型(第一种比较方式:通过元素自身的比较方式)

    ------->TreeSetDemo02类:<---------

    package com.JavaStudy01.Set;
    
    import com.JavaStudy01.Bean.Person;
    
    import java.util.Iterator;
    import java.util.TreeSet;
    
    /**
     * @Author wufq
     * @Date 2020/8/6 10:06
     */
    public class TreeSetDemo02 {
        public static void main(String[] args){
            TreeSet ts = new TreeSet();
            ts.add(new Person("zhangsan",23));
            ts.add(new Person("lisi",24));
            ts.add(new Person("wangwu",25));
            ts.add(new Person("zhaoliu",26));
    
            Iterator it = ts.iterator();
            while (it.hasNext()){
                Person p = (Person)it.next();
                System.out.println(p.getName()+"::"+p.getAge());  //报com.JavaStudy01.Bean.Person cannot be cast to java.lang.Comparable异常
            }
        }
    
        /*
        Comparable:此接口强行对实现他的每一个类的对象进行整体排序,这种排序被称为类的自然排序,类的compareTo方法被称为自然比较方法
        如何才能解决可以比较的对象:
    
         */
    }
    =====执行结果=====
    报com.JavaStudy01.Bean.Person cannot be cast to java.lang.Comparable异常
     

    通过查Comparable异常发现:此接口强行对实现他的每一个类的对象进行整体排序,这种排序被称为类的自然排序,类的compareTo方法被称为自然比较方法

    如何才能解决可以比较的对象:person类继承Comparable接口,并重写compareTo方法

    int compareTo():比较此对象与指定对象的大小,如果该对象小于,大于,等于指定对象,则分别返回负整数,正整数,零

    --------->Person类继承Comparable接口<---------

    package com.JavaStudy01.Bean;
    
    /**
     * @Author wufq
     * @Date 2020/7/31 11:24
     */
    public class Person implements Comparable{
        private String name;
        private int age;
    
        public Person() {
        }
    
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        @Override
        public int hashCode() {
    //        System.out.println(this+"........hachCode");//验证是否真的在调用hashCode方法
            return name.hashCode()+age;
        }
    
        @Override
        public boolean equals(Object obj) {
            Person p= (Person)obj;
    
    //        System.out.println(this+"........equals"+obj);//验证是否真的在调用equals方法
            //this表示谁去调用就是谁
            return this.name.equals(p.name)&&this.age == p.age;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public int getAge() {
            return age;
        }
    
        public String toString(){
            return name+"::"+age;
        }
    
        @Override
        public int compareTo(Object o) {
            Person p = (Person)o;
            //通过年龄的大小进行判断,如果年龄相同在通过名字进行判断
            if(this.age < p.age){
                return -1;
            }else if(this.age > p.age){
                return 1;
            }else if(this.age == p.age){
                return this.name.compareTo(p.name);
            }
    
            //另外一种判断写法
            int temp = this.age - p.age;
            return temp==0?this.name.compareTo(p.name):temp;//temp=0吗,等于就对name进行比较,不等于就返回temp
        }
    }

    重新执行Person的结果:

    zhangsan::23
    lisi::24
    wangwu::25
    huqi::26
    zhaoliu::26

    ------->通过结果可以看出已经完成了排序

     3、比较自定义类型(第二种比较方式:通过集合本身具备比较功能)

    ------->定义一个ComparatorByName类实现Comparator接口<---------

    package com.JavaStudy01.Set;
    
    import com.JavaStudy01.Bean.Person;
    
    import java.util.Comparator;
    
    /**
     * @Author wufq
     * @Date 2020/8/6 14:37
     */
    public class ComparatorByName implements Comparator{
    
        @Override
        public int compare(Object o1, Object o2) {
            Person p1 = (Person)o1;
            Person p2 = (Person)o2;
    
            int temp = p1.getName().compareTo(p2.getName());
            return temp==0?p1.getAge()-p2.getAge():temp;
        }
    }

    ------->TreeSetDemo02类<-------

    package com.JavaStudy01.Set;
    
    import com.JavaStudy01.Bean.Person;
    
    import java.util.Iterator;
    import java.util.TreeSet;
    
    /**
     * @Author wufq
     * @Date 2020/8/6 10:06
     */
    public class TreeSetDemo02 {
        public static void main(String[] args){
            TreeSet ts = new TreeSet(new ComparatorByName());
            ts.add(new Person("zhangsan",23));
            ts.add(new Person("lisi",24));
            ts.add(new Person("wangwu",25));
            ts.add(new Person("zhaoliu",26));
            ts.add(new Person("huqi",26));
    
            Iterator it = ts.iterator();
            while (it.hasNext()){
                Person p = (Person)it.next();
                System.out.println(p.getName()+"::"+p.getAge());  //报com.JavaStudy01.Bean.Person cannot be cast to java.lang.Comparable异常
            }
        }
    }
    ======执行结果======
    huqi::26
    lisi::24
    wangwu::25
    zhangsan::23
    zhaoliu::26

    4、TreeSet底层结构,来判断如何确定元素的比较

     5、字符串长度排序

    ------->定义一个ComparatorByString类实现Comparator接口<---------

    package com.JavaStudy01.Set;
    
    import java.util.Comparator;
    
    /**
     * @Author wufq
     * @Date 2020/8/6 15:27
     */
    public class ComparatorByString implements Comparator{
        @Override
        public int compare(Object o1, Object o2) {
            String s1 = (String)o1;
            String s2 = (String)o2;
    
            int temp = s1.length() - s2.length();
    
            return temp==0?s1.compareTo(s2):temp; //这里的compareTo是String类自身的比较方法,而非集合内的比较方法
        }
    }

    ------->TreeSetDemo03排序<---------

    package com.JavaStudy01.Set;
    
    import java.util.Iterator;
    import java.util.TreeSet;
    
    /**
     * @Author wufq
     * @Date 2020/8/6 15:27
     */
    public class TreeSetDemo03 {
        public static void main(String[] args){
            TreeSet ts = new TreeSet(new ComparatorByString());
    
            ts.add("aa");
            ts.add("abcd");
            ts.add("zzzzzz");
            ts.add("hhl");
            ts.add("kkk");
    
            Iterator it = ts.iterator();
    
            while (it.hasNext()){
                System.out.println(it.next());
            }
        }
    
    }
    ====执行结果=====
    aa
    hhl
    kkk
    abcd
    zzzzzz

     

  • 相关阅读:
    [bzoj 3048] [Usaco2013 Jan]Cow Lineup
    [bzoj 3192] [JLOI2013]删除物品
    搬迁至新博客的原因
    洛谷 P3317 [SDOI2014]重建(矩阵树定理+数学推导) [bzoj3534]
    [bzoj1002]: [FJOI2007]轮状病毒(矩阵树定理)
    [bzoj1006]: [HNOI2008]神奇的国度(最大势算法)
    高精度板子
    洛谷 P3211 [HNOI2011]XOR和路径(推dp+高斯消元)
    字符串--manacher算法(回文串匹配)
    洛谷 P2633 Count on a tree[bzoj2588](倍增lca+主席树)
  • 原文地址:https://www.cnblogs.com/frankruby/p/13410775.html
Copyright © 2020-2023  润新知