hashcode、equals和compareTo、compare方法的意义及作用

时间:2020-11-30 16:22:16

一、hashcode和equals必须同时在类中重写(让equals方法和hashCode方法始终在逻辑上保持一致性


import java.util.HashMap;
 class Dog {
private String name;
private Integer age;
public Dog(){}
public Dog(String name, Integer age) {
this.name = name;
this.age = age;
}
         //重写hashCode方法,比较hash值(hash值是哈希表中的数据)
//哈希表是一种数据结构,它提供了快速的插入操作和查找操作。其基于数组来实现。 
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((age == null) ? 0 : age.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
//重写equals方法
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Dog other = (Dog) obj;
if (age == null) {
if (other.age != null)
return false;
} else if (!age.equals(other.age))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
 }
public class HashCodeAndEqualsInfo{
/**
* 测试
* 对于两个对象,如果调用equals方法得到的结果为true,则两个对象的hashcode值必定相等;
*                          如果equals方法得到的结果为false,则两个对象的hashcode值不一定不同;
* 但是
*         如果两个对象的hashcode值不等, 则equals方法得到的结果必定为false;
*         如果两个对象的hashcode值相等, 则equals方法得到的结果未知

*/
public static  void  main(String args[]){
/**
* 在HashSet、HashMap以及HashTable插入操作中,类中数据如果是String类型,一定需要实现hashCode和equals方法
*/
Dog dog = new Dog("Marry", 22);
        System.out.println("hashCode:"+dog.hashCode());
             
        HashMap<Dog, Integer> hashMap = new HashMap<Dog, Integer>();
        hashMap.put(dog, 36);
         //如果没有重写hashCode或者equals方法,那么打印null而不是36;
        /**原因是没有重写hashCode方法,那么会认为name和age是指向同一个地址即hash值是:33311724
         * 如果重写了hashCode和equals方法,那么打印结果是:74115696
         */
        System.out.println("结果:"+hashMap.get(new Dog("Marry", 22)));
}
}

二、compareTo方法和compare的意义及作用

1、普通的类要实现排序,必须实现Comparable接口,并重写CompareTo()方法。 

2、compareTo(Object o)方法是java.lang.Comparable<T>接口中的方法,当需要对某个类的对象进行排序时,

      该类需要实现Comparable<T>接口的,

      必须重写public int compareTo(T o)方法,比如MapReduce中Map函数和Reduce函数处理的 <key,value>,

      其中需要根据key对键值对进行排序,

      所以,key实现了WritableComparable<T>接口,实现这个接口可同时用于序列化和反序列化。

       WritableComparable<T>接口  (用于序列化和反序列化)是Writable接口和Comparable<T>接口的组合;

3、compare(Object o1,Object o2)方法是java.util.Comparator<T>接口的方法,它实际上用的是待比较对象的compareTo(Object o)

举例说明:

新建一个Cat.java类

package com.util.compare;
public class Cat implements Comparable<Object>{
    int id;               //id
    String name; //name
    public Cat(int id,String name){
        this.id = id;
        this.name = name;
    }
    public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
   /**
     * 重写compareTo方法
     */

    @Override
    public int compareTo(Object o) {
        if(this ==o){
            return 0;            
        }
        else if (o!=null && o instanceof Cat) {   
        Cat u = (Cat) o; 
            if(id<=u.id){
                return -1;
            }else{
            return 1;
        }
    }else{
        return -1;
    }

}
}


新建一个测试类:TestClass.java

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class TestClass {
    //编写Comparator,根据Cat的id对Cat进行排序
    private static final Comparator<Cat> COMPARATOR = new Comparator<Cat>() {
       public int compare(Cat o1, Cat o2) {
           return o1.compareTo(o2);//运用Cat类的compareTo方法比较两个对象       
      }
   };
    public static void main(String[] args) {
        ArrayList<Cat> cat = new ArrayList<Cat>();
        Cat c1 = new Cat(1,"xiaohei");
        Cat c2 = new Cat(2,"xiaohei");
         cat.add(c1);
         cat.add(c2);
        Collections.sort(cat, COMPARATOR);//使用我们写好的Comparator对cat进行排序

        //如果是数组排序则使用:Arrays.sort(数组名);
        for(int i=0;i<cat.size();i++){
            System.out.println("结果:"+cat.get(i).getId());
        }
    }
}

三、单独使用CompareTo方法

@Test
    public void testCpm(){
    /**compareTo()的返回值是整型,它是先比较对应字符的大小(ASCII码顺序),
    * 如果第一个字符和参数的第一个字符不等,结束比较,返回他们之间的差值
    * 如果第一个字符和参数的第一个字符相等,则以第二个字符和参数的第二个字符做比较,
    * 以此类推,直至比较的字符或被比较的字符有一方全都比较完,这时就比较字符的长度. 
    * 结论:compareTo比较一定要比较出差值!
    *              如果字符串的ascll都比较完,但str和mes中的每一个字符还是相等,
    *              那么就比较字符串长度的差值(如str6和mes6比较)
    */
    String str="a"; String mes="b";
    String str2="abc"; String mes2="a";
    String str3="abdc"; String mes3="2d";
    String str4="abcde"; String mes4="ab";
    String str5="acd"; String mes5="2br";
    String str6="acd"; String mes6="acd";
    /**a的ascll码是97,1的ascll码是49*/
    System.out.println("结果一:"+str.compareTo(mes));      //-1
    System.out.println("结果二:"+str2.compareTo(mes2)); //2
    System.out.println("结果三:"+str3.compareTo(mes3)); //47
    System.out.println("结果四:"+str4.compareTo(mes4)); //3
    System.out.println("结果五:"+str5.compareTo(mes5)); //47
    System.out.println("结果六:"+str6.compareTo(mes6)); //0
    }