首页 > 学院 > 开发设计 > 正文

[Effective Java]第三章 对所有对象都通用的方法

2019-11-14 22:44:21
字体:
来源:转载
供稿:网友
[Effective java]第三章 对所有对象都通用的方法声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.VEVb.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将追究法律责任!原文链接:http://www.VEVb.com/jiangzhengjun/p/4255581.html 第三章 对所有对象都通用的方法 8、 覆盖equals时请遵守通用约定

如果类具有自己特定的“逻辑相等”概念(不同于对象等同概念),而且超类还没有覆盖equals以实现期望的行为,这时我们就需要覆盖equals方法,这通常属于“值类”的情形,例如Integer或者是Data,程序员在利用equals方法来比较值对象的引用时,希望知道它们在逻辑上是否相等,而不是想了解它们是否指向同一个对象。

在覆盖equals方法时,你必须要遵守它的通用约定。下面是约定的内容,来自Object的规范:

l自反性:对于任何非null的引用值xx.equals(x)必须返回true。如果自已不等于自己的话,将其放入集合中后,该集合的contains方法将告诉你,集合中不包括你刚添加的实例。

l对称性:对于任何非null的引用值xy,当且仅当y.equals(x)返回true时,x.equals(y)必须返回true。这就要求不同类的实例如果在逻辑值相同的情况下,要求这两个实例所对应的类的equals方法比较逻辑要相同,不然的话,对称性将不再满足。

l传递性:对于任何非null的引用值xyz,如果x.equals(y)返回true,并且y.equals(z)也返回true,那么x.equals(z)也必须返回true

l一致性:对于任何非null的引用值xy,只要equals的比较操作在对象中所用的信息没有被修改,多次调用x.equals(y)就会一致地返回true,或者一致地返回false

l非空性:对于任何非null的引用值xx.equals(null)必须返回false

实现高质量的equals方法:

1、使用==操作符检查“参数是否为这个对象的引用”。如果是,则返回true,这只不过是一种性能优化,如果比较操作有可能很昂贵,就值得这么做。

2、使用instanceof操作符检查“参数是否为正确的类型”。如果不是,则返回false。一般说来所谓“正确的类型”是指定equals所在的那个类。有些情况下,是指该类所实现的某个接口。如果类实现的接口改进了equals约定,允许在实现了该接口的类之间进行比较,那么就使用接口。集合接口如SetListMapMap.Entry具有这样的特性。注,这步会过滤掉null,因为null instanceof XX一定会返回false。另外,要注意的是,如果你只与自己本身类型的类相比,则可以使用if(getClass() == obj.getClass())来限制为同一个类比较而不希望是父类或其子类(思想来源于《PRactice Java》)。

3、把参数转换成正确的类型。因为转换之前进行过instanceof测试,所以确保会成功。

4、对于该类中的每个“关键”域,检查参数中的域是否与该对象中对应的域相匹配。如果这些测试全部成功,则返回true,否则返回false

对于既不是float也不是double类型的基本类型域,可以使用==操作符进行比较;对于对象引用域,可以递归地调用equals方法;对于float域,可以使用Float.compare方法;对于double域,则使用Double.compare。对于数组域,则要把以上这些指导原则应用到每个元素上,如果数组域中的每个元素都需要比较的话,可以使用1.5版本中发行的Arrays.equals方法。

对于floatdouble域进行特殊的处理是有必要的,因为存在着Float.NaN-0.0f以及类似的double常量,详细信息请参考Float.equals的文档,看看Float.equals源码与文档描述:

publicbooleanequals(Object obj) {

return(objinstanceofFloat)

&& (floatToIntBits(((Float) obj).value) == floatToIntBits(value));

}

在比较是否相等时使用是floatToIntBits(float)方法,即将浮点的二进制位看作是整型位后比较的。注意,在大多数情况下,对于Float类的两个实例f1f2,让f1.equals(f2)的值为true的条件是当且仅当f1.floatValue() == f2.floatValue()的值也为true。但是也有下列两种例外:

l如果f1f2都表示Float.NaN(规定Float.NaN = 0x7fc00000),那么即使Float.NaN = = Float.NaN的值为falseequals方法也将返回true(因为他们所对应的整型位是相同的)。

l如果f1表示+0.0f,而f2表示-0.0f,或相反的情况,则equal测试返回的值是false(因为他们所对应的整型位是不同的),即使0.0f = = -0.0f的值为true也是如此。

另外,来看看Float.compare的源码:

publicstaticintcompare(floatf1,floatf2) {

if(f1 < f2)

return-1; // Neithervalis NaN, thisVal is smaller

if(f1 > f2)

return1; // Neithervalis NaN, thisVal is larger

intthisBits = Float.floatToIntBits(f1);

intanotherBits = Float.floatToIntBits(f2);

return(thisBits == anotherBits ? 0 : // Values are equal

(thisBits < anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN)

1)); // (0.0, -0.0) or (NaN, !NaN)

}

compare是从数字上比较两个Float对象。在应用到基本float值时,有两种方法来比较执行此方法产生的值与执行Java语言的数字比较运算符(<<===>= >)产生的那些值之间的区别:

l该方法认为Float.NaN将等于其自身,且大于其他所有float值(包括Float.POSITIVE_INFINITY)。

l该方法认为0.0f将大于-0.0f

请记住,如果是通过Java语言的数字比较运算符(<<===>= >)而不是compare方法来比较时,只要其中有一个操作为Float.NaN,那么比较结果就是false

对象引用域的值为null是有可能的,所以,为了避免可能导致的空指针异常,则使用下面的作法:

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表