• 2004-04-05

    读《Effective Java》-笔记7

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://pcmanlin.blogbus.com/logs/128676.html

    读《Effective Java》-笔记7
    Chapter 3 所有对象的通用方法

    虽然Object类是一个具体类,主要用途是进行扩展。但是,它的所有非空方法(equals,hashCode,toString,clone和finalize)都有明确的“通用契约”,它们的设计初衷就是“被重写”。任何类重写这些方法都必须遵循这些规则。

    简介:

    Item7:重写equals方法时遵循通用契约

     

    全文:

    Item7:重写equals方法时遵循通用契约

        重写equals方法看起来简单,但是有很多方式可能导致错误的发生。最简单就是不重写equals方法,就不会出错了。但是这种方式,一般应用于下面的条件发生的时候:

        a) 每个类的实例在其继承体系中是独一无二的。

        b) 并不关心类是否提供“逻辑等价”的测试。

        c) 超类已经重写了equals方法,从超类继承来的行为同样也适用于子类

        d) 一个类属于私有类或者所属包属于私有包,可以确定类的equals方法不会被调用。

       

    何时重写Object的equals方法才合适?

        当一个类试图进行逻辑等价比较,进而进行纯粹的对象一致性检验时,同时,超类又没有重写equals方法实现必要的行为。比较两个值对象一般是希望发现它们是否逻辑上等价,而不是它们是否是指向同一个对象的引用。

    型别安全的enum,不需要重写equals方法,因为型别安全的enum类确保了每个对象最多只存在一个值。

     

    重写equals方法,必须遵循下面的通用契约:自反性、对称性、传递性、一致性。

    自反性-一个对象至少应该和它自己相等。

    对称性-两个对象必须符合x.equals(y)和y.equals(x)结果一致的通用契约。面对这个契约更好的办法是将类型不同和内容不同均视为equals()返回值为false。

    传递性x.equals(y)成立,y.equals(z)成立,则x.equals(z)成立。

     

        没有简单的方法可以扩展自一个可实例化的类并向其中添加一个字段,还能保证遵循equals契约。但是,往往可以通过组合,不使用继承,来解决这个问题。

        一致性-如果两个对象相等,它们必须一直都保持相等,除非其中一个改变。

        “非空”-所有的对象都必须不等于null。

     

    编写高质量的equals方法:

    1)  使用==运算符来检查参数是否是自身对象的引用。

    2)  使用instanceof运算符检查参数型别是否正确。

    3)  将参数转型为正确的型别,前面已经使用instanceof确保了型别。

    4)  对于类中的每个“重要”字段,检查这个字段是否与这个对象的相应字段相符。如果,所有这些测试都成功,返回true;否则,返回false。

    a)       对于基本型别,只要不是float或者double,可以用==运算符进行比较。

    b)       对于对象引用字段,必须递归调用equals方法。

    c)       对于float字段,使用Float.floatToIntBits将它转换成int值,然后用==进行比较

    d)       对于double字段,使用Double.doubleToLongBits将它转换成long值,然后用==进行比较

    5)  写完equals方法,对对称性、传递性和一致性进行考核。

     

    最后的一些告诫:

    1)  当你重写equals方法,相应的重写hashCode()方法。

    2)  Don’t try to be too clever.

    3)  不要编写依赖于不可靠资源的equals方法。

    4)  Don’t substitute another type for Object in the equals declaration.

     


    历史上的今天:

    Struts 控制器 2004-04-05

    收藏到:Del.icio.us




    引用

    下面Blog引用了该文: