美文网首页
***3.Set子接口(不重复)

***3.Set子接口(不重复)

作者: 秋笙fine | 来源:发表于2019-02-11 20:41 被阅读0次

    1.Set子接口的操作特点以及常用子类

    2.深入分析两个常用子类的操作特征

    3.分析TreeSet如何实现排序/排序情况下,判断重复元素

    4.分析重复元素判断依据(Object类的HashCode,equals)/HashSet去重/非排序情况下,判断重复元素

    在Collection接口下又有另外一个比较常用的子接口Set接口(20%).
    Set接口并不像List接口那样对Collection接口进行大量的扩充。而是简单的继承了Collection接口。也就没有了之前List集合所提供的get方法

    Set接口下有两个常用的子类:HashSet(基于HashMap,而HashMap基于数组和链表,无序排列),TreeSet(基于TreeMap 而TreeMap基于红黑树,Comparable接口实现的有序排序)

    范例:观察HashSet子类的特点

    public class TestDemo{
        
        public static void main(String[] args) throws Exception{
    
            Set<String> all=new HashSet<String>();
            all.add("NIHAO");
            all.add("Hello");
            all.add("Hello");//重复数据
            all.add("World");
            System.out.println(all);
        }
    
    }
    

    结果


    image.png

    发现数据不重复而且无序

    通过演示可以发现,Set集合下没有重复元素(Set接口特征),并且保存的数据是没有顺序的,即:HashSet子类的特征属于无序排列。

    范例:观察TreeSet子类

    
        public static void main(String[] args) throws Exception{
    
            Set<String> all=new TreeSet<String>();
            all.add("X");
            all.add("B");
            all.add("A");//重复数据
            all.add("B");
            System.out.println(all);
        }
    

    结果:


    image.png

    此时程序使用了TreeSet子类,发现没有重复数据(Set接口特征),保存的内容自动排序(通过Comparable接口实现的排序)。

    关于数据排序的说明

    既然TreeSet子类保存的内容可以进行排序,下面就不如编写一个自定义的类来保存数据:

    class Book{
        private String title;
        private double price;
        public Book(String title,double price){
            this.title=title;
            this.price=price;
        }
        @Override
        public String toString() {
            return "Name:"+this.title+"price:"+this.price;
        }
    }
    public class TestDemo{
        
        public static void main(String[] args) throws Exception{
        
            Set<Book> all=new TreeSet<Book>();
            System.out.println("length:"+all.size()+" is empty:"+all.isEmpty());
            all.add(new Book("Java",20.8));
            all.add(new Book("Java",20.8));//全部信息重复
            all.add(new Book("Android",20.8));//价格信息重复
            all.add(new Book(".NET",30.7));//都不重复
            System.out.println(all);
            
        }
    
    }
    
    

    报错了,报错信息为


    image.png

    很明显,在进行对象数组排序的时候,一定要使用比较器。应该使用Comparable进行比较。(定义比较规则)并且在比较方法中,需要将这个类的所有属性都参与到比较之中

    class Book implements Comparable<Book>{
        private String title;
        private double price;
        public Book(String title,double price){
            this.title=title;
            this.price=price;
        }
        @Override
        public String toString() {
            return "Name:"+this.title+"price:"+this.price;
        }
    
        @Override
        public int compareTo(Book o) {
            if(this.price>o.price){
                return 1;
            }
            if(this.price<o.price){
                return -1;
            }
            return 0;
        }
    }
    public class TestDemo{
        
        public static void main(String[] args) throws Exception{
        
            Set<Book> all=new TreeSet<Book>();
            System.out.println("length:"+all.size()+" is empty:"+all.isEmpty());
            all.add(new Book("Java",20.8));
            all.add(new Book("Java",20.8));//全部信息重复
            all.add(new Book("Android",20.8));//价格信息重复
            all.add(new Book(".NET",30.7));//都不重复
            System.out.println(all);
            
        }
    
    }
    

    结果:


    image.png

    我们发现,价格相同的,它也认为重复了。

    因此通过检测我们可以判断,TreeSet是通过Comparable接口的CompareTo方法来判断是否是重复数据,如果返回的是0,就认为是重复数据,不会被保存。

    所以最终的代码需要比较title与price:

    class Book implements Comparable<Book>{
        private String title;
        private double price;
        public Book(String title,double price){
            this.title=title;
            this.price=price;
        }
        @Override
        public String toString() {
            return "Name:"+this.title+"price:"+this.price;
        }
    
        @Override
        public int compareTo(Book o) {
            if(this.price>o.price){
                return 1;
            }
            if(this.price<o.price){
                return -1;
            }
            return this.title.compareTo(o.title);
        }
    }
    public class TestDemo{
        
        public static void main(String[] args) throws Exception{
        
            Set<Book> all=new TreeSet<Book>();
            System.out.println("length:"+all.size()+" is empty:"+all.isEmpty());
            all.add(new Book("Java",20.8));
            all.add(new Book("Java",20.8));//全部信息重复
            all.add(new Book("Android",20.8));//价格信息重复
            all.add(new Book(".NET",30.7));//都不重复
            System.out.println(all);
            
        }
    
    }
    

    最终结果也实现了按照title和price两个属性排序。


    image.png
    关于重复元素的说明

    很明显,Comparable接口只能够负责TreeSet子类进行重复元素的判断,它并不是真正的能够用于进行重复元素验证的操作。如果要想判断重复元素,那么只能够依靠Object类中所提供的方法。
    取得哈希码:public int hashCode()
    先判断对象的哈希码是否相同,依靠哈希码取得一个对象的内容
    对象比较:public boolean equals(Object obj)
    再将对象的属性进行依次的比较。

    Tips:可以使用IDEA的generate生成hashCode和equals。

    由于HashSet基于HashMap,基于数组和链表,有基本的哈希算法进行比较,所以其仍会出现重复数据(虽然内存地址不同),此时如果要进行真正意义上重复数据的比较,则覆写Object的hashCode和equals方法来去重。

    class Book {
        private String title;
        private double price;
    
        public Book(String title, double price) {
            this.title = title;
            this.price = price;
        }
    
        @Override
        public String toString() {
            return "Name:" + this.title + "price:" + this.price;
        }
        
    }
    
    public class TestDemo {
    
        public static void main(String[] args) throws Exception {
    
            Set<Book> all = new HashSet<Book>();
            System.out.println("length:" + all.size() + " is empty:" + all.isEmpty());
            all.add(new Book("Java", 20.8));
            all.add(new Book("Java", 20.8));// 全部信息重复
            all.add(new Book("Android", 20.8));// 价格信息重复
            all.add(new Book(".NET", 30.7));// 都不重复
            System.out.println(all);
    
        }
    
    }
    

    上面代码加上IDE生成的hashCode和equals完成hashSet的去重。

    以后在非排序的情况下,只要是判断重复元素依靠的永远都是hashCode与equals

    总结:

    1.在开发之中,Set接口绝对不是首选,如果真要使用也建议使用HashSet子类
    2.Comparable这种比较器大部分情况下只会存在于Java理论范畴内,例如:要进行TreeSet。
    3.Set不管如何操作,必须始终保持一个前提:数据不能够重复。

    相关文章

      网友评论

          本文标题:***3.Set子接口(不重复)

          本文链接:https://www.haomeiwen.com/subject/jctceqtx.html