Effective Java 笔记(三)


NO.7 在改写equals方法时请遵守通用约定
下列情况是不需要改写equals方法的:
1。同一个类的不同实例本质上是唯一的,就是个实例都有自己的本体(Identify)。
2。不关心该类是否提供了逻辑相等的功能。
3。父类已经改写过equals方法,对于子类来说,继承过来的equals方法已经是最合适的了。
4。一个类是私有的或者是包可见的,且确定它的equals方法不会被调用。
 
对于需要改写equals方法的时候,应该遵守如下约定:
1。自反性,即x.equals(x)为true.
2。对称性,即当且仅当x.equals(y)为true时y.equals(x)也一定为true。
3。传递性,即对任意的x,y,z,如果x.equals(y)为true,并且y.equals(z)也为true,那么x.equals(z)也必须为true.
4。一致性,即对于任意的x,y,如果x,y都没有被修改的话,那么多次调用x.equals(y)要么一致地返回ture,要么一致地返回false.
5。对于非空的引用x,x.equals(null)一定要返回false.
 
改写equals方法时的建议:
1。用==操作符检查实参是否为指向对象的同一个引用。
2。使用instanceOf检查实参是否是正确的类型。
3。在2的基础上,把实参转换成正确的类型。
4。检查实参的域与当前对象的域值是否相等。
5。编写完equals方法后,检查是否满足等价关系。
例如:
  1. public boolean equals(Object o)
  2. {
  3.        if(o== thisreturn true;
  4.        if(!(o instanceof xxxx) return false;
  5.        xxx in = (xxx)o;
  6.        return ……..
  7. }
改写equals方法的告诫:
1、不要企图让equals方法做太多事。
2、不要使equals依赖不可靠的资源,否则会违背一致性。
3、不要将equals中的对象装换为其他的类型。
4、要注意的时候不要提供这样的方法public boolean equals(MyClass o)这样是重载并不是覆盖Object的equals方法。
总结:不用重写equals方法就尽量不要去找麻烦,确实需要改写equals方法时,遵守通用约定,因为对象会在程序中不停的传递,所以可能会导致程序运行不正常,甚至崩溃而很难找到程序崩溃的原因。总之,还是遵守约定吧!

NO.8 改写equals方法时必须覆盖hashCode方法
       这点必须切忌,不然在你和hash-based集合打交道的时候,错误就会出现了。关键问题在于一定要满足相等的对象必须要有相等的hashCode。如 果你在PhoneNumber类中覆盖了equals方法,但是没有覆盖hashCode方法,那么当你做如下操作的时候就会出现问题了。
  1. Map m = new HashMap();
  2. m.put(new PhoneNumber(408,863,3334),”ming”)
当 你调用m.get(new PhoneNumber(408,863,3334))的时候你希望得到ming但是你却得到了null,为什么呢因为在整个过程中有两个 PhoneNumber的实例,一个是put一个是get,但是他们两个逻辑相等的实例却得到不同的hashCode那么怎么可以取得以前存入的ming 呢。


NO.9 总是要改写toString()方法
        在Object的toString方法返回的形式是Class的类型加上@加上16进制的hashcode,非常难以理解。最好在自己的类中提供toString方法更好的表述实例的信息,不然别人怎么看得明白呢。
        在实际应用中,toString方法应该返回对象中包含的所有令人感兴趣的信息。同时,最好在程序中提供一个相匹配的构造函数或者静态工厂方法,便于程序员在对象和它的字符串表示之间进行来回转换。
       在实现toString方法的时候,必须要做出是否在文档中指定返回值的格式的决定。指定格式可以被用来做为一种标准的,无二意性的表达形式,但这样也会使字符串的表示嵌入到永久数据中,如果以后改变了表达形式,则会影响到系统的代码和数据。不管你是否决定指定格式,都应该在代码中清晰的表明自己的意图。可在所在的类中为toString返回值中所包含的信息提供一种编程访问途径,用来获取toString方法返回字符串中的信息,避免程序员自己去解析字符串而导致的错误。


NO.10 谨慎地改写clone(clone方法详解请参见 java clone方法使用详解
      一个对象要想被Clone,那么要实现Clone()接口,这个接口没有定义任何的方法,但是如果你不实现这个接口的话,调用clone方法的 时候会出现CloneNotSupportedException,这就是作者叫做mixin的接口类型。通常clone()方法可以这样覆盖
 
但是当你要clone的类里面含有可修改的引用字段的时候,那么你一定要把整个类的蓝图进行复制,如果对你clone得到的对象进行修改的时候还会影响到原来的实例,那么这是不可取的。所以应该这样clone()

其中elements是stack类中可修改的引用字段,注意如果elements是final的话我们就无能为力了,因为不能给他重新赋值了.其实如果不是必须的话,根本就不用它最好。
      clone方法如果实现得不当会给系统带来隐藏的bug,如果非要使用类似的功能最好的办法是提供某些其他的途径(拷贝构造函数或者提供一个静态工厂方法来替代构造函数)来替代对象的拷贝,或者干脆不提供这样的能力。
      Cloneable有很多问题,所以安全的说,其他的接口不应该扩展(extend)这个接口,并且为了继承而设计的类也不应该实现(implement)这个接口。


NO.11 考虑实现Comparable接口
      compareTo方法是java.lang.Comparable接口中的唯一方法,它允许进行简单的相等比较,也允许执行顺序比较,一个类实现了comparable接口就表明他的实例具有内置的排序关系。Java平台库中所有的值类都实现了Comparable。将当前对象与指定对象进行顺序比较的时,返回负整数,0或者正整数(<、=、>),如果指定对象的类型无法进行比较,则抛出ClassCastException或者NullPointException异常,compareTo方法应遵守如下限制条件:自反性、对称性、传递性和非空性的限制条件。在实现数值比较的compareTo方法时还要防止值域溢出的情况。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值