Set接口的使用

Set介绍

HashMap和HashSet里面的键值和对象的不相等

在Java的集合中,判断两个对象是否相等的规则是:

  1. 判断两个对象的hashCode是否相等
    如果不相等,认为两个对象也不相等,完毕
    如果相等,转入2)
    (这一点只是为了提高存储效率而要求的,其实理论上没有也可以,但如果没有,实际使用时效率会大大降低,所以我们这里将其做为必需的。后面会重点讲到这个问题。)
  2. 判断两个对象用equals运算是否相等
    如果不相等,认为两个对象也不相等
    如果相等,认为两个对象相等(equals()是判断两个对象是否相等的关键)
  3. HashMap不允许有相等的键值,HashSet不允许有相等的对象元素。
    说一下hashCode和equal的区别,其实我们的底层都是hashCode进行比较的,也就是说,一个对象的equals一样的话,那么它的哈市Code是一样的,

    @Override
    public int hashCode() {
        // TODO Auto-generated method stub
        return 一个int数;
    }
    @Override
    public boolean equals(Object obj) {
        // TODO Auto-generated method stub
        return this==obj;
    }
    

    一般来说,我们的equals一样是,那么他们的地址是一样的(这是java规定的),但是如果他们的equals不相等的话,那么他们的hashCode不确定,为什么?因为hashCode的算法决定的。例如一个类的hashCode的算法是:

        @Override
    public int hashCode() {
        // TODO Auto-generated method stub
        return this.name.hashCode()+this.password.hashCode();
    }
    @Override
    public boolean equals(Object obj) {
        // TODO Auto-generated method stub
        if(obj==null){
            return false;
            }
        User user=(User)obj;
        if(obj==this){
            return true;
        }
    
        if(this.name.equals(user.getName())&&this.password.equals(user.getPassword())){
            return true;
        }
    
        return false;
    }
    

    hashCode返回一个int值,当自定义的时候就可能返回一个不一样的值。如果没有被覆写的话,那就返回的是哈希算法的结果。在我们覆写的方法里面,我们要按照jdk的要求,如果覆写了equals的话,那么hashCode是一定要覆写的,而且,如果equals相等的话,那么hashCode是一定要相等的。因为两个相等的对象的hashCode是一定一样的。
    当你使用HashSet的时候,add的时候调用的hashCode和equals是你覆写过的方法。
    总结:在使用Set的时候,保证两个元素是否相等的关键就是两个方法,hashCode和equals,一般是先比较hashCode,如果不相等,则两个对象不一样,如果相等,则进行equals的比较,如果一样则两个对象是一样的(同一内存的引用)。一般使用hashCode的原因是提高hashMap的效率和性能。所以,当我们的项目有要求的时候,我们是需要自己覆写hashCode和equals方法的。

    HashSet和TreeSet

    使用HashSet的时候,将元素放到内存的时候,是乱序放入的,也就是和你的java语句的顺序是无关的,但是使用TreeSet的时候是会自动排序的。
    TreeSet的使用:

  4. 类要实现Comparable接口,覆写比较的方法 int compareTo(T o)

    @Override
    public int compareTo(User o) {
        System.out.println("比较方法被调用!");
        // TODO Auto-generated method stub
        int x= this.name.compareTo(o.getName());
        if(x==0){
        return    this.password.compareTo(o.getPassword());
        }
        return x;
     }
    

    先比较什么,在再比较什么可由你自己决定。一个类实现了Comparable接口后,它的set就变得有序了,就算你使用的是HashSet,也不在是乱序插入。但是不是排序的,这一点和TrssSet还是有区别的。

    TreeSet

    这个接口是谁TreeSet的子接口,使用SortedSet接口的子类是可以排序的子类,SortedSet的基本用法和TreeSet是一样的,在本章的例子里面我们主要就是熟悉一下其获取第一个和最后一个以及在两个在指定的元素之间的所有元素这三个方法。
    在前面我们知道,实现Set接口的类是不能有重复的元素存在的,这个的保证就是hashCode和equals方法,但是,set接口无法实现排序(既然所有元素不相等,我们可以考虑加入排序操作),所有就有了TreeSet接口,实现这个接口的时候记得覆写我们的comparableTo方法实现自己的排序规则。