Effecitive Java 读书笔记 (一)

第三章:对于所有对象都通用的方法


(1)覆盖equal时,请遵守通用约定

            

在重写任何类的equals方法是必须遵循以下几点:

1、对称性:如果x.equals(y)返回是“true”,那么y.equals(x)也应该返回是“true”。

2、反射性:x.equals(x)必须返回是“true”。

3、类推性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那么z.equals(x)也应该返回是“true”。 

4、还有一致性:如果x.equals(y)返回是“true”,只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是“true”。

5、任何情况下,x.equals(null),永远返回是“false”;

 

在实现高质量equals方法的诀窍:

1,使用= = 操作符检查“参数是否为这个对象的引用”。如果是,则返回true。

2.  使用instanceof 操作符(如果的子类都拥有统一的语义)检查"参数是否为正确类型“,"正确类型"是指equals方法所在的类

3.  把参数转换成正确的类型

4. 对于该类的每个"关键"域,检查参数中的域是否与该对象中的域匹配。使用= = 比较基本类型域,使用equals比较对象域。

5.当你编写完equals方法以后,问自己:它是否是对称的,传递的,一致的。


(1)覆盖equal时总要覆盖hashCode

当我们向一个集合中添加某个元素,集合会首先调用hashCode方法,这样就可以直接定位它所存储的位置,若该处没有其他元素,则直接保存。若该处已经有元素存在,就调用equals方法来匹配这两个元素是否相同,相同则不存,不同则散列到其他位置


对于hashCode,我们应该遵循如下规则:

     1. 在一个应用程序执行期间,如果一个对象的equals方法做比较所用到的信息没有被修改的话,则对该对象调用hashCode方法多次,它必须始终如一地返回同一个整数。

     2. 如果两个对象根据equals(Object o)方法是相等的,则调用这两个对象中任一对象的hashCode方法必须产生相同的整数结果。

     3. 如果两个对象根据equals(Object o)方法是不相等的,则调用这两个对象中任一个对象的hashCode方法,不要求产生不同的整数结果。但如果能不同,则可能提高散列表的性能。

因没有覆盖hashcCode而违反的关键约定是第二条,会导致两个相等的实例具有不同的的散列码

    

至于euqals 和hashCode两者之间的关联关系,我们只需要记住如下即可:

      如果x.equals(y)返回“true”,那么x和y的hashCode()必须相等。

      如果x.equals(y)返回“false”,那么x和y的hashCode()有可能相等,也有可能不


编写hashCode:

     1.把某个非零的常数值,比如说17,保存在一个result  名字的int类型变量中

      2.对于对象中每个关键域(指equals方法中涉及的每个域) 完成两个步骤:(1)为该域计算int类型的散列码c (2)按照 result = 31 *result + c 公式进行合并处理

      3.返回result

注意:(1)在散列码计算过程中,如果一个域的值可以通过其它域计算出来,则计算hashCode不用计算它。(2)必须要排除equals比较计算中没有用到的任何域


(3)始终要要覆盖toString

toString方法用于 返回表示对象值的字符串,在实际应用中,toString方法应该返回对象中包含的所有值得关注的信息


编写toString:

       1.决定是否在文档中指定返回值的格式

      2.无论决定是否指定返回值的格式,都应该在文档中明确表明你的意图

      3.无论决定是否指定返回值的格式,都为toString返回值中包含的所有信息,提供一种编程式的访问途径(即在类中提供它们的访问方法)


(4)谨慎地覆盖clone

      当拷贝变量时,原始变量与拷贝变量引用同一个对象,这就是说改变一个不安看所引用的对象将会对另一个对象产生影响。拷贝的目的是为了,是拷贝的对象 与原对象相互独立,各自改变状态而相互不影响

       clone类必须要实现Cloneable接口,Cloneable接口是不包含任何方法的!它决定Object中受保护的的clone方法实现的行为:如果clone类没有实现Cloneable接口,并调用了Object的clone()方法(也就是调用了super.Clone()方法),那么Object的clone()方法就会抛出CloneNotSupportedException异常

        

编写Clone方法要注意的:

         1. 默认的克隆操作是浅拷贝,它并没有克隆包含在对象中的内部对象,如果对象中包含的域引用了可变的对象,使用默认clone方法可能会导致灾难性的后果,clone方法就是一个构造器:你必须确保它不会伤害到原始的对象,并确保正确地创建被克隆对象中的约束条件,对于对象中包含的域引用了可变的对象,要实现深拷贝

        2.所有拷贝都要实现Cloneable 接口,并且首先调用super.clone().如果要实现深拷贝,必须克隆所有可变的实例域。这意味者要拷贝任何包含内部"深层结构"的可变对象,并用指向新对象的引用代替原来指向这些对象的引用,往往通过递归地调用clone来完成但这通常不是最佳方法。如果该u对象只包含基本类型的域或者指向不可变对象的引用,那么多半情况下是没有域需要修正

       3.克隆复杂对象的的方法:先调用super.clone(),然后把结果对象中的所有域都设置成它们的空白状态,然后调用高层的方法来重新产生对象的状态

       4.在大部分情况下,没有必要搞得这么复杂。克隆的应用并不没有那么普遍

  

5)考虑实现Comparable接口


  编写Clone方法要注意的:

              1.compareTo方法的通用约定与 equals方法相似,域equals不同的是,跨越不同类的时候, compareTo方法可以不做比较,如果两个被比较对象引用不同的类的对象,compareTo可以抛出ClassCastException异常

          2.违反 compareTo约定的类也会破坏其它依赖于比较关系的类。依赖比较关系的类包括有序集合类TreeSet和TreeMap,以及工具类Collections和Arrays,它们内部包含有搜索和排序算法

         3.如果一个人类有多个关键域,你必须从最关键的域开始,逐步进行到所有的重要域。如果某个域的比较产生了非零的结果(零代表相等),则整个比较操作结束,并返回该结果。如果最关键域相等,则进一步比较次最关键的域,以此类推。如果所有的域都是相等的,则对象就是相等的,并返回零

        4. 如果一个域并没有实现Comparable接口,或者你需要一个非标准的排序关系,就可以使用一个显式的Comparator来代替Comparator可以看成一种算法的实现,将算法和数据分离,Comparator也可以在下面两种环境下使用:
     (1)类的设计师没有考虑到比较问题而没有实现Comparable,可以通过Comparator来实现排序而不必改变对象本身
     (2)可以使用多种排序标准,指定多种排序方法来提高灵活性,比如升序、降序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值