《Effective Java》(7~8)阅读笔记

来源:互联网 发布:mysql主键从1000开始 编辑:程序博客网 时间:2024/06/08 07:13

接着上期继续看本书高质量编码建议7、8条的阅读笔记

7.避免使用最终方法

此处所谓的终结方法指的就是finalize()方法,这个方法可能对于从C++转向Java的新手感到混淆,因为在C++中有一个“析构函数”,析构函数所代表的意义就是在这个对象垃圾回收前所做的一些动作例如资源的关闭等。对于Java来说垃圾回收是自动的,或者称之为不可预知或不可控,尽管finalize方法所代表的也是在垃圾回收前所做的一些动作,但对于GC的时间你不能掌握,也就是说不能保证finalize方法会被及时执行,这是很危险的,一般情况下这个方法不会被用到。

  终结方法既然存在那它就并不是毫无用处,第一种用途就是充当一个“安全网”,终结方法“本该”是在GC前做一些清理动作,但GC的时间未知,也就是终结方法执行时间未知,对于FileInputStream类我们都知道应该在try-finally中对其调用close方法,但也许我们会忘记编写此方法,在FileInputStream源代码中就实现了终结方法目的就在于如果忘记了close方法,至少还有终结方法,虽然可能不能得到及时执行,但晚执行总比不执行好吧。第二个用途可能使用的场景就可能比较少,JVM只回收普通对象,对于本地对象(也就是不是Java实现的对象),JVM并不会对它进行回收,此时我们就可以在终结方法中对本地对象进行一些清理操作,但一定记住一定要是“不拥有关键资源的前提”,且在子类中重写了终结方法一定要现实调用super.finalize(),否则父类的终结方法不会被调用。

  综上,对于终结方法,一般代码中并不会使用,如果要使用一定要考虑上面两种用途是否值得去做,万万不应该依赖终结方法来更新重要的持久状态

8.覆盖equals时请遵守通用约定

对于equals方法,在编码中最常用的可能就是比较两个字符串是否是值相等的。需要自己重写equals方法的场景可能并不是人人都能有幸碰到,而如果碰到了该怎么办,本条目下书中说明了重写equals方法时需要遵守的一些通用约定,如果不遵守这些约定可能导致无法和其他类配合使用。

  equals方法来自于Object类:

        public boolean equals(Object obj){

               return(this == obj)

        }

 可以看到在Object类中equals比较的两个实例是否是引用相等的,换句话说,在不考虑“值相等”的情况下,每个实例都是独一无二的,每个实例都只与它自身相等。何时需要重写equals方法呢?顶级类只提供了引用是否相等,如果你需要自己实现一个逻辑是否相等,此时则需要重写equals方法,例如String类,但当在重写equals方法时,应该遵守以下约定:

  自反性:对于任何非null的引用值x,x.equals(x)必须返回true。也就是说一个类的实例一定是与它本身相等的,不管你怎么实现它的逻辑判断,但它的“本”不能忘。

  对称性:对于任何非null的引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)必须返回true。这条比较好理解,x=1,y=1,你不能y=x而x!=y吧。

  传递性:对于任何非null的引用值x、y和z,如果x.equals(y)返回true,并且y.equals(z)也返回true,那么x.equals(z)也必须返回true。显而易见。

  一致性:对于任何非null的引用值x和y,只要equals的比较操作在对象中的所用的信息没有被修改,多次调用x.equals(y)就会一致地返回true,或者一致地返回false。这条显然,你不能多调用判断几次它的结果就产生变化了吧。

  对于任何非null的引用值x,x.equals(null)必须返回null。

  一定要反复检查测试自己重写的equals方法是否遵守以上约定,否则程序可能会变得不正常,因为许多类,包括所有的集合类都依赖于是否遵守了equals约定。书中举了详细的例子来说明上述约定,这里不再叙述。

  我们来分析下String类中重写的equals方法:

//String.equals       public boolean equals(Object anObject) {           if (this == anObject) {    //是否等于自身                return true;           }          if (anObject instanceof String) {    //类型是否相等             String anotherString = (String) anObject;    //转换类型             int n = value.length;                 if (n == anotherString.value.length) {    //先判断长度是否相等                    char v1[] = value;                    char v2[] = anotherString.value;                    int i = 0;                    while (n-- != 0) {    //一个一个字符判断值是否相等                        if (v1[i] != v2[i])                                return false;                          i++;                      }                        return true;                }           }             return false;        }

String中equals方法的实现实际上就是书中给我们的重写equals的一些诀窍:

  1、使用==操作检查“对象是否为这个对象的引用”,这不是必须的,只是作为一种性能优化,例如Integer类中并无此项判断。

  2、使用instanceof操作符检查“参数是否为正确的类型”。

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

  4、对于该类中的每个“关键”域,检查参数中的域是否与该对象中对应的域想匹配。




原创粉丝点击