对于所有对象都通用的方法

import java.util.*;
public class OverrideObjectMethod {

	public static void main(String[] args) {
		
		Map<PhoneNumberBad, String> map = new HashMap<PhoneNumberBad, String>();
		map.put(new PhoneNumberBad(110, 86, 1351), "chenzq");
		//Object的hashCode实现返回对象的引用地址,所以equals相等的2个对象会返回不一样的hashCode
		String result = map.get(new PhoneNumberBad(110, 86, 1351));
		System.out.println(result);	//null

		Map<PhoneNumber, String> mp = new HashMap<PhoneNumber, String>();
		mp.put(new PhoneNumber(110, 86, 1351), "chenzq");
		
		result = mp.get(new PhoneNumber(110, 86, 1351));
		System.out.println(result);	//chenzq
		
		System.out.println(new PhoneNumber(110, 86, 1351));
		
		PhoneNumber[] arr = new PhoneNumber[5];
		arr[0] = new PhoneNumber(110, 86, 1351);
		arr[1] = new PhoneNumber(110, 87, 1351);
		arr[2] = new PhoneNumber(110, 87, 1350);
		arr[3] = new PhoneNumber(111, 86, 1352);
		arr[4] = new PhoneNumber(114, 80, 1354);
		
		Arrays.sort(arr);
		
		for(PhoneNumber pn : arr) {
			System.out.println(pn);
		}
	}

}

class PhoneNumber implements Comparable<PhoneNumber> {
	private final int areaCode;
	private final int prefix;
	private final int lineNumber;
	
	public PhoneNumber(int areaCode, int prefix, int lineNumber) {
		this.areaCode = areaCode;
		this.prefix = prefix;
		this.lineNumber = lineNumber;
	}
	
	@Override public int compareTo(PhoneNumber o) {
		// Compare area codes
		int areaCodeDiff = areaCode - o.areaCode;
		if (areaCodeDiff != 0)
			return areaCodeDiff;
		// Area codes are equal, compare prefixes
		int prefixDiff = prefix - o.prefix;
		if (prefixDiff != 0)
			return prefixDiff;
		// Area codes and prefixes are equal, compare line numbers
		return lineNumber - o.lineNumber;
	}
	
	@Override public boolean equals(Object o) {
		if (o == this)
			return true;
		if (!(o instanceof PhoneNumber))
			return false;
		PhoneNumber pn = (PhoneNumber) o;
		return pn.lineNumber == lineNumber
			&& pn.prefix == prefix
			&& pn.areaCode == areaCode;
	}
	
	@Override public int hashCode() {
		int result = 17;
		result = 31 * result + this.areaCode;
		result = 31 * result + this.prefix;
		result = 31 * result + this.lineNumber;
		return result;
	}
	
	@Override public String toString() {
		return String.format("(%03d) %03d-%04d", this.areaCode, this.prefix, this.lineNumber);
	}
}

class PhoneNumberBad {
	private final int areaCode;
	private final int prefix;
	private final int lineNumber;
	
	public PhoneNumberBad(int areaCode, int prefix, int lineNumber) {
		this.areaCode = areaCode;
		this.prefix = prefix;
		this.lineNumber = lineNumber;
	}
	
	@Override public boolean equals(Object o) {
		if (o == this)
			return true;
		if (!(o instanceof PhoneNumberBad))
			return false;
		PhoneNumberBad pn = (PhoneNumberBad) o;
		return pn.lineNumber == lineNumber
			&& pn.prefix == prefix
			&& pn.areaCode == areaCode;
	}
}

 输出为:

null
chenzq
(110) 086-1351
(110) 086-1351
(110) 087-1350
(110) 087-1351
(111) 086-1352
(114) 080-1354

 * 对于所有对象都通用的方法:
   尽管Object是一个具体类,但设计它主要是为了扩展。它所有的非final方法

  (equals/hashCode/toString/clone/finalize)都有明确的通用约定。
   因为它们被设计成是要被覆盖的。任何一个类在覆盖这些方法时,都有责任遵守这些通用约定。否则

   其他依赖于这些约定的类(HashMap/HashSet),就无法结合该类一起正常工作。

 * 什么时候应该override equals方法:如果类具有自己特有的“逻辑相等”概念(不同于对象等同),

   而且超类还没有覆盖equals以实现期望的行为时,需要覆盖equals。

***************************************************************
 * 覆盖equals时请遵守通用约定:
   自反型:对于任何非null的引用值x,x.equals(x)必须返回true。
   对称性:对于任何非null的引用值x和y,x.equals(y)返回true时,y.equals(x)也必须返回true。
   传递性:对于任何非null的引用值x、y和z,x.equals(y)返回true并且y.equals(z)也返回true时,

                 x.equals(z)也必须返回true。
   一致性:对于任何非null的引用值x和y,只要x和y对象所用的比较信息没有修改,多次调用

                 x.equals(y)的结果应该一致。
   非空性:对于任何非null的引用值x,x.equals(null)必须返回false。

                 null instanceof 任何类型都会返回false,所以不需要判断比较对象是否为null。

 * 使用instanceof检查参数是否为正确的类型,并把参数转换为正确的类型。
 * 对于非float和double的基本类型使用==进行比较,对象引用field可以递归调用equals比较,

扫描二维码关注公众号,回复: 663947 查看本文章

   float类型使用Float.compare方法,double使用Double.compare。
 * 有些对象field包含null值是合法的,为了避免NullPointerException,使用:

   (field == null ? o.field == null : field.equals(o.field))
 * 不要企图让equals过于智能。
 * 不要将equals声明中的Object替换为其他类型(使用强类型参数,只是重载了equals方法,

    并没有覆盖equals方法)。@Override注解可以避免这种错误。

 ****************************************************************
 * 覆盖equals时总要覆盖hashCode:
   在每个覆盖了equals的类中也必须覆盖hashCode,否则就会违反Object.hashCode的通用约定,

   从而导致该类无法结合所有基于散列的集合正常工作(HashMap/Hashtable/HashSet)。
   在应用程序运行期间,只要对象equals方法比较所用到的field信息没有被修改,那么对这一对象

   多次调用hashCode必须始终返回同一个整数。
 * 如果两个对象调用equals比较是相等的,那么两个对象的hashCode也必须返回相同的整数。
 * 如果两个对象调用equals比较是不相等的,那么两个对象的hashCode不一定要返回不同的整数。

   但是给不同的对象截然不同的hashCode整数结果有可能提高散列表的性能。

***************************************************************
 * 始终要覆盖toString:
   toString通用约定指出,被返回的字符串应该是一个“简洁的,但信息丰富,并且易于阅读的表达形式”。

   建议所有的子类覆盖toString方法。在实际应用中,toString应该返回所有值得关注的信息。


***************************************************************
 * 类实现了Comparable接口,就表明它的实例具有内在的排序关系(natural ordering)。

   Arrays.sort(arr) 当该对象小于、等于、大于指定对象的时候,分别返回一个负整数、零、正整数。
 * compareTo方法的通用约定:
   必须确保所有的x和y都满足,x.compareTo(y) == - (y.compareTo(x))。
   必须确保比较关系是可传递的,x.compareTo(y) > 0 && y.compareTo(z) > 0 则 x.compareTo(z) > 0
   强烈建议: (x.compareTo(y) == 0) == (x.equals(y))

猜你喜欢

转载自jaesonchen.iteye.com/blog/2286866