学习地址: 

    1、我们为什么需要重写hashCode()方法和equals()方法
    
    首先equals() 与hashCode()方法是Java父类Object定义的方法;
    源代码中是如此定义的两个方法:
    public native int hashCode();
    public boolean equals(Object obj) {
        return (this == obj);
    }
    Java中的超类Object类中定义的equals()方法是用来比较两个引用所指向的对象的内存地址是否一致
    Object类中的hashCode()方法,用native关键字修饰,说明这个方法是个原生函数,也就说这个方法的实现不是用java语言实现的,是使用c/c++实现的,并且被编译成了DLL,由java去调用,jdk源码中不包含。对于不同的平台它们是不同的,java在不同的操作系统中调用不同的native方法实现对操作系统的访问,因为java语言不能直接访问操作系统底层,因为它没有指针。

    Java的API文档对hashCode()方法做了详细的说明,这也是我们重写hashCode()方法时的原则【Object类】

    重点要注意的是:

    a.  在java应用程序运行时,无论何时多次调用同一个对象时的hsahCode()方法,这个对象的hashCode()方法的返回值必须是相同的一个int值

    b.  如果两个对象equals()返回值为true,则他们的hashCode()也必须返回相同的int值

    c.  如果两个对象equals()返回值为false,则他们的hashCode()返回值也必须不同
    
    2、在什么情况下需要重写hashCode()方法和equals()方法
    
    我们在定义类时,我们经常会希望两个不同对象的某些属性值相同时就认为他们相同,所以我们要重写equals()方法,按照原则,我们重写了equals()方法,也要重写hashCode()方法,要保证上面所述的b,c原则;所以java中的很多类都重写了这两个方法,例如String类,包装类
    当我们自定义的一个类,想要把它的实例保存在集合中时,我们就需要重写这两个方法;
        如果使用自定义的类来作为TreeMap中的key值,且想让TreeMap能够良好的工作,则必须重写自定义类中的equals()方法,TreeMap中判断相等的标准是:两个key通过equals()方法返回为true,并且通过compareTo()方法比较应该返回为0。

        当向HashSet结合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据 hashCode值来决定该对象在HashSet中存储位置。简单的说,HashSet集合判断两个元素相等的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode()方法返回值也相等。
        注意,如果要把一个对象放入HashSet中,重写该对象对应类的equals方法,也应该重写其hashCode()方法。其规则是如果两个对象通过equals方法比较返回true时,其hashCode也应该相同。另外,对象中用作equals比较标准的属性,都应该用来计算 hashCode的值。
    
    
    3、如何重写这两个方法

         以集合类TreeMap为例:

package com.basic.util;
 
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.TreeMap;
 
public class BasicTreeMap {
	public static void main(String[] args) {
		Student s1 = new Student("lpn", 27, 61.38);
		Student s2 = new Student("tbn", 28, 62.211);
		Student s3 = new Student("xyz", 29, 63.345);
		Student s4 = new Student("qwe", 30, 64.986);
		
		TreeMap<Student, Integer> tMap = new TreeMap<Student, Integer>(new StudentCmp());
		tMap.put(s1, 1);
		tMap.put(s4, 4);
		tMap.put(s2, 2);
		tMap.put(s3, 3);
		tMap.put(s1, 100);
		tMap.put(s3, null);
		tMap.remove(s3);
		
		Iterator<Entry<Student, Integer>> iterr = tMap.entrySet().iterator();
		while (iterr.hasNext()) {
			Entry<Student, Integer> e = iterr.next();
			if (e.getKey().equals(s4)) {
				iterr.remove();
			}
		}
		
		/** Caused Exception java.util.ConcurrentModificationException
		for (Entry<Student, Integer> e : tMap.entrySet()) {
			if (e.getValue() == 2) {
				tMap.remove(e.getKey());
			}
		}
		*/
		
		Iterator<Entry<Student, Integer>> iter = tMap.entrySet().iterator();
		while (iter.hasNext()) {
			Entry<Student, Integer> e = iter.next();
			System.out.println(e.getKey().toString() + " " + e.getValue());
		}
		
		for (Entry<Student, Integer> e : tMap.entrySet()) {
			System.out.println(e.getKey().toString() + " " + e.getValue());
		}
	}
}
 
 
class Student implements Comparable<Student> {
	private String name;
	private int age;
	private double height;
	
	public Student() {
	}
	
	public Student(String name, int age, double height) {
		this.name = name;
		this.age = age;
		this.height = height;
	}
	
	
	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}
 
	/**
	 * @param name the name to set
	 */
	public void setName(String name) {
		this.name = name;
	}
 
	/**
	 * @return the age
	 */
	public int getAge() {
		return age;
	}
 
	/**
	 * @param age the age to set
	 */
	public void setAge(int age) {
		this.age = age;
	}
 
	/**
	 * @return the height
	 */
	public double getHeight() {
		return height;
	}
 
	/**
	 * @param height the height to set
	 */
	public void setHeight(double height) {
		this.height = height;
	}
 
	@Override
	public int hashCode() {
		int result = 1;
		final int prime = 31;
		result = result*prime + name == null ? 0 : name.hashCode();
		result = result*prime + age;
		result = result*prime + (int) Double.doubleToLongBits(height);
		return result;
	}
	
	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (null == obj) {
			return false;
		}
		if (!(obj instanceof Student)) {
			return false;
		}
		Student s = (Student) obj;
		if (name != null) {
			if (s.name == null || !name.equals(s.name)) {
				return false;
			}
		} else {
			if (s.name != null) {
				return false;
			}
		}
		if (age != s.age) {
			return false;
		}
		if (Double.doubleToLongBits(height) != Double.doubleToLongBits(s.height)) {
			return false;
		}
		return true;
	}
	
	@Override
	public String toString() {
		String str = "";
		str = name + " " + age + " " + height;
		return str;
	}
 
	@Override
	public int compareTo(Student o) {
		if (this.age < o.age) {
			return -1;
		} else if (this.age > o.age) {
			return 1;
		}
		return 0;
	}
}
 
class StudentCmp implements Comparator<Student> {
 
	@Override
	public int compare(Student o1, Student o2) {
		if (o2.getAge() < o1.getAge()) {
			return -1;
		} else if (o2.getAge() > o1.getAge()) {
			return 1;
		}
		return 0;
	}
	
}


最后某些特殊情况下,可能需要基于value排序,下面的代码实现了基于value排序,并考虑了value为null的情况

List<Entry<Student, Integer>> lEntry = new ArrayList<Entry<Student, Integer>>(tMap.entrySet());
		Collections.sort(lEntry, new Comparator<Entry<Student, Integer>> () {
			@Override
			public int compare(Entry<Student, Integer> o1, Entry<Student, Integer> o2) {
				if (o1.getValue() != null && o2.getValue() != null) {
					return o2.getValue() - o1.getValue();
				} else if (o1.getValue() == null) {
					return 1;
				} else {
					return -1;
				}
			}
		});