Effective Java:Ch3_Methods:Item8_重写equals方法时遵循通用约定(四)

2014-11-24 11:59:54 · 作者: · 浏览: 133
s(Object o) {
if (!(o instanceof MyType))
return false;
MyType mt = (MyType) o;
}
如果没有类型检查,当equals的参数传入了一个错误的类型,则equals会抛出ClassCastException,违反约定。但是如果instanceof的第一个操作符是null,则一定返回false。也就是说,如果传入null,则类型检查就会返回false,不需要单独的null检查。
总结
总而言之,实现高质量的equals方法有如下诀窍:
1)使用==操作符来判断参数是否为该对象的一个引用。如果是,则返回true。这只不过是一种性能优化,当比较操作开销很大时,就值得这么做。
2)使用instanceof操作符来判断参数是否是正确的类型。如果不是,则返回false。一般来说,正确的类型就是equals方法所在的类。偶尔情况下,是该类实现的某个接口。如果类使用的接口优化了equals约定,允许在实现该接口的不同类间进行比较,那就使用接口。集合接口Set、List、Map、Map.Entry都有这种特性。
[java]
public interface Set{
/**
* Compares the specified object with this set for equality. Returns
* true if the specified object is also a set, the two sets
* have the same size, and every member of the specified set is
* contained in this set (or equivalently, every member of this set is
* contained in the specified set).
>>>>>>>>>
This definition ensures that the
* equals method works properly across different implementations of the
* set interface.
*
* @param o object to be compared for equality with this set
* @return true if the specified object is equal to this set
*/
boolean equals(Object o);
public abstract class AbstractSet implements Set {
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Set))
return false;
Collection c = (Collection) o;
if (c.size() != size())
return false;
try {
return containsAll(c);
} catch (ClassCastException unused) {
return false;
} catch (NullPointerException unused) {
return false;
}
}
}
3)将参数强制转换为正确的类型。因为之前进行了instanceof测试,这里的强制转换能确保成功。
4)遍历类中的每个关键域,检查参数中的域与对象本身的域是否匹配。如果测试成功返回true,否则返回false。如果Step2中的类型是一个接口,则需要通过接口方法来访问参数中的域;如果是类,则也许能直接访问参数的域,这要取决于域的可见性。
对于不是float和double的基本类型,用==操作符进行比较;对于对象引用,则递归调用equals;对于float域,使用Float.compare方法;对于double域,调用Double.compare方法。对float和double域的特殊处理是有必要的,因为存在Float.NaN、-0.0f,以及类似的double常量,可参考Float.equals方法。
[java]
//Float.equals
/*
注意,在大多数情况下,对于 Float 类的两个实例 f1 和 f2,让 f1.equals(f2) 的值为 true 的条件是当且仅当
f1.floatValue() == f2.floatValue()
的值也为 true。但是也有下列两种例外:
1) 如果 f1 和 f2 都表示 Float.NaN,那么即使 Float.NaN==Float.NaN 的值为 false,equals 方法也将返回 true。
2) 如果 f1 表示 +0.0f,而 f2 表示 -0.0f,或相反的情况,则 equal 测试返回的值是 false,即使 0.0f==-0.0f 的值为 true 也是如此。
*/
public boolean equals(Object obj) {
return (obj instanceof Float)
&& (floatToIntBits(((Float)obj).value) == floatToIntBits(value));
}
对于数组域,则对每个元素进行比较。如果数组中的每个元素都重要,可以使用JDK1.5的Arrays.equals方法。
[java]
//Arrays.equals
public static boolean equals(Object[] a, Object[] a2) {
if (a==a2)
return true;
if (a==null || a2==null)
return false;
int length = a.length;
if (a2.length != length)
return false;
for (int i=0; i
Object o1 = a[i];
Object o2 = a2[i];
if (!(o1==null o2==null : o1.equals(o2)))
return false;
}
return true;
}
对象引用可能包含null,为避免可能发生的NullPointException,