2017.6.12 hashSet, TreeSet, Comparable及Comparator

Q:

  • 重写equals时候可以不重写HashCode,覆盖HashCode的时候必须要覆盖equals如何理解
  • Set中底层添加数据的过程,如何实现的无序
  • 列举HashSet删除数据的几种方式,简述注意事项,如何添加数据,忽略大小写的实现
  • 二叉树存取过程演示
  • 对象比较实现Comparable时,如何实现多级比较?如何实现两种比较规则,如升序,降序?(两个比较器),TreeSet首选哪种方式Comparable还是Comparator?
  • 根据java规则,一个实现类需要实现所继承接口全部的抽象类,而为什么comparator没有实现Comparator接口的两个compareTo和equals?
    Debug Set和ArrayList的数据添加过程

*** Q:重写equals时候可以不重写HashCode,覆盖HashCode的时候必须要覆盖equals如何理解 ***

A:
看比较规则如何定义:
如果允许属性相同仅通过HashCode()来比较对象是否相同时候可以只写equals,但通常不这样做
但如果重写HashCode,说明通过HashCode来比较对象,HashCode相同,所以一定要规定equals方法来明确比较规则
HashSet在执行增删改查的时候是先执行HashCode再执行equals的

*** Q:Set中底层添加数据的过程,如何实现的无序 ***
A:添加过程: HashSet->HashCode- - ->equals
先创建HashMap,为一个容量16的数组
1 HashSet会自动调用Student的HashCode,得到Student的int值HashCode的num1
2 HashSet对num1进行一系列的运算,得到int2的num2
3 HashSet对num2进行num2%16运算得到num3,则为该数据存放的索引值,进行存放
4 如果有索引重复的情况,后添加的元素会以链表的形式添加到之前元素位置的next里
5 加载因子为0.75,则数据量大于12的时候,会严重影响访问速度,HashSet自动扩容,重新分配元素数组的位置1~3操作使用%31操作
6 如果HashCode不同,则数据直接进入集合
7 如果HashCode相同,HashSet会再次调用equals,如果equals为true,则不允许数据进入集合,如果为false,则可以进入集合,由于HashCode决定数组索引,则后面元素都存放在相同位置

*** Q:列举HashSet删除数据的几种方式,简述注意事项 ***
可以通过遍历器删除,需要注意在遍历过程中找到目标元素后停止遍历:

Iterator it = set.iterator();
        while (it.hasNext()) {
            Course c = it.next();
            if (c.getName().equals(name)) {
                // 在遍历Set集合的过程中,可以通过迭代器来删除数据.这样迭代器的状态和集合的状态不会错乱.再次遍历Set集合
                // 不会发生ConcurrentModificationException异常
                // 我们在使用迭代器从Set集合中删除数据之后,Set集合中就不会再有这样的数据了,也就没有必要再遍历集合了
                // 所以应该中断循环
                it.remove();
                return true;
            }
        }
        return false;
    }
    
也可以使用给定的数据创建对象,直接删除,更加快捷:
public boolean removeCourse3(String name) {
        // c这个数据本身是否在集合中存在?根本就不存在.因为c这个数据是新new出来的,根本就没有向集合中添加过
        Course c = new Course(name);

        // set.contains(c)这个方法并不是查询c这个数据本身是否在集合中存在.而是查询的集合中是否有对象的内容
        // 和c这个对象的内容一致.
        // 那么是如何查询的呢?
        if (set.contains(c)) {
            return set.remove(c);
        }
        return false;
    }
    

添加数据,忽略大小写的实现
需要在重写equals方法和hashCode方法时做一些调整:


public boolean equals(Object obj){
        if(this == obj)
            return true;
        
        if(obj instanceof Course){
            Course course = (Course)obj;
            if(this.name.equalsIgnoreCase(course.name)) // 忽略大小写
                return true;
        }
        return false;
            
    }
    
    public int hashCode(){
        return (this.name.toLowerCase().hashCode())*31; //字符串类型全部转换为小写
    }
    

*** 二叉树存取过程演示 ***

*** 对象比较实现Comparable时,如何实现多级比较?如何实现两种比较规则,如升序,降序?(两个比较器),TreeSet首选哪种方式Comparable还是Comparator?***
多级比较可以在重写CompareTo方法时候加上判断条件,如下,现根据年龄,再根据姓名排序:

public int compareTo(Person p){
        if(this.age!=p.age){
            return this.age-p.age;
        }
        else{
            return add.compareTo(p.add);
        }
            
    }

实现两种比较规则并灵活切换,需要使用比较器:
Set set = new TreeSet<>(new StudentComparator1());//创建对象时传递个比较器参数进取给TreeSet的构造方法
public class StudentComparator1 implements Comparator {

@Override
public int compare(Student o1, Student o2) {

    // 根据第一个参数小于、等于或大于第二个参数分别返回负整数、零或正整数。
    if (o1.getAge() > o2.getAge()) {
        return 1;
    } else if (o1.getAge() < o2.getAge()) {
        return -1;
    }

    return o1.getName().compareTo(o2.getName());
}

}

*** 根据java规则,一个实现类需要实现所继承接口全部的抽象类,而为什么comparator没有实现Comparator接口的两个compareTo和equals?
从Obeject继承来了equals方法,所以无需重写 ***

*** Debug Set和ArrayList的数据添加过程 ***


*** Summary:***
hashCode() / equals()方法面试题 Student.java:
察看集合的错误的删除方式,察看Student.java,注意在遍历集合的过程中,要中断循环

重写equals时候可以不重写HashCode,覆盖HashCode的时候必须要覆盖equals,通常情况下,这两个方式都要同时覆盖
在HashSet中添加,查询,删除都需要调用HashCode(),equals()
最佳的删除方式是创建新对象,删除集合中相同的元素,注意当需要忽略大小写的时候,在equals方法时候,忽略大小写:具体操作HashCode()统一转大写
统一转小写,equals方法,把equals用ignore
二叉树存取过程演
二叉树中添加,修改数据都需要使用Compare规则
实现比较规则的不同方式,Comparable, Comparator(实现多种规则并存)
LinkedList和ArrayList特点

你可能感兴趣的:(2017.6.12 hashSet, TreeSet, Comparable及Comparator)