{Effective Java} Chap 3 对于所有对象都适用的方法

Object is designed for extension. All of its nonfinal methods(equals, hashCode, toString, clone, finalize) have explicit general contracts. It is the responsibility of any class oberriding these methods to obey their general contracts. This chapter will tell you when and how to override the nonfinal Object methods. Comparable.compareTo is also discussed because it has similar character.


第八条:覆盖equals 注意遵守通用约定

When not to override:

Each instance of the class is inherently unique.

You don't care whether the class provides a logical equality.

A super class has overridden equals. And sub class can use it.

The class is private or package private and equals will never be invoked.


Value class: 在类具有自己特有的逻辑相等的概念时可以进行覆盖equals. 

Instance control:  such as Enum has only one object, so don't need to override equals.


1.6 的 equivalence relation 约定:

reflexive, symmetric, transitive and consistent(多次调用结果一致,x.equals(null) 对于非null的x 始终返回false).


高质量equals

1. 用 == 检查 是否引用同一个对象

2. instanceof 检查 参数是否为正确的类型

3. 把参数转为正确的类型

4. 对于 significant 域,检查参数中的域是否与该对象匹配

    float: Float.compare()

    double: Double.compare()

    其他基本类型: ==

    对于可能出现null的:  field == null ? object.field == null : field.equals(object.field)

    如果field 与 object.field 是相同的对象引用: field == object.field || ( field != null && field.equals( object.field ))

5. 不要把equals中的object声明改掉


第九条:覆盖equals 同时也要覆盖 hashCode

1.6 规范:

1. 只要equals用到的信息没有修改,那么该对象的hashCode不会变

2. 如果equals,那么hashcode必须一致

3. 如果不equals,那么hashcode也可能相同


编写好的hashCode()

不相等的对象产生不同的散列码。

1. int result 为某个非0常数值,如17

2. 对于每个关键域 f 

2.1 对于 f 计算int类型的散列码 c

    a. boolean : f ? 1:0

    b. byte/char/short/int: (int) f

c. long : (int) (f ^ (f >>> 32))

  d. float : Float.floatToIntBits( f )

e. double:Double.doubleToLongBits( f ),然后按照 c 计算散列值

        f. 对象引用并且该类的equals 方法通过递归调用 equals 来比较,那么也递归 hashCode()

  g.如果该域为null,返回0

  h. 数组,可以对每个元素单独应用上述规则。或者Arrays.hashCode

2.2 上述所有计算后得到的c 

result = 31 * result + c

3. 返回result

4. Unit test 是否相等实例具有相同的散列码


分析:

计算hashcode时可以排除equals比较时没用到的域。

非零初始值对hashcode进行一定的影响。

2.2 中的乘法使得 hashcode依赖于域的顺序。

选择31 是因为它是奇素数,可以用 移位和减法代替乘法,利于优化。 31 * i = ( i << 5 ) - i

如果类不可变,且计算hashcode代价大,那么可以缓存 hashcode。

//lazily initialized, cached hashCode
private volatile int hashCode;

@Override
public int hashCode()
{
    int result = hashCode;
    if( result == 0)
    {
        result = 17;
        result = 31 * result + areaCode;
        result = 31 * result + prefix;
        result = 31 * result + lineNumber;
        hashCode = result;
    }

    return result;
}

不要通过减少对象关键域来提高性能。



第十条: always override toString()

无论是否制定toString的格式,都应该进行说明。并且对于toString返回值中包含的信息,提供访问方法。

例如:

/*
Returns a brief description of this position.
The exact details of the representation are unspecified and subject to change,
but the following may be regarded as typical:

"[Position: x=1, y=2]"
*/



第十一条:pay attention to clone()

clone就是另一个构造器,必须确保它不会伤害原始对象,并确保正确创建被克隆对象的约束条件。

clone与引用可变对象的final域的正常用法不兼容。

最好使用其他方法代替拷贝,例如copy constructor/ factory

public Test(Test test);   

public static Test newInstance(Test test);

不要使用Cloneable()接口。


第十二条:考虑实现Comparable接口

实现了comparable接口的类具有 natural ordering, 通过调用 Arrays.sort() 进行排序。

当编写value class时,考虑实现comparable, 它就能和 generic algorithm, collection implementation 合作。

当对象小于,等于,大于指定对象时,分别返回负整数,0,正整数。

建议: 

( a.compareTo(b) == 0 ) == (a.equals( y ))

comparable 不必进行类型检查,不必对参数进行转换。比较域时,从最重要的开始。

注意:留意域之间的差距会不会导致溢出



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Anyanyamy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值