Effective Java读书笔记二(Java Tips.Day.2)

Tip6. 消除过期的对象引用


  • 只要类自己管理内存,就应该警惕内存泄漏问题。一旦元素被释放,则该元素中包含的任何对象引用都应该被清空。
  • 缓存对象的管理不当,可能会导致内存泄漏。
  • 监听器和其它回调。应当在合适的时候注销掉已注册的回调监听器,或者只保存它们的弱引用。

Tip7. 避免使用终结方法


请务必合理的使用终结方法。Java语言规范不仅不保证终结方法会被及时地执行,而且根本就不保证它们会被执行。而且它们还会造成性能损失。

  • 显示的终止方法常与try-finally结构结合起来使用,以确保及时终止。在finally字句内部调用显示的终结方法,可以保证及时有异常抛出,终止方法也会执行。比如I/O流的关闭,Timer的cancel等等。

Tip8. 覆盖equals


选择不覆盖equals

覆盖equals没有看起来的那么简单,经常会导致错误。最容易避免这类问题的办法就是不覆盖equals,在这种情况下,每个实例都只与它自身相等。

容易导致错误的情况如下:

  • 类的每个实例本质是唯一的。对于代表活动实体,而不是值(value)的类来说,确实如此,例如Thread。Object类提供的equals实现对于这些类就足够了。
  • 不关心类是否提供了”逻辑相等(logical equality)”的测试功能。
  • 超类已经覆盖了equals,从超类继承过来的行为对于子类也是合适的。例如大多数Set实现都从AbstractSet继承equals实现,List和Map的很多实现与此类似。
  • 类是private或package的,可以确定它的equals方法永远不会被调用。在这种情况下,可以覆盖equals并直接抛出一个错误或异常,确保它不会被调用。

选择覆盖equals

如果类具有自己特有的”逻辑相等”的概念(不同于对象等同),而且超类还没有覆盖equals以实现期望的行为,这时我们就需要覆盖equals。


约定的equals规范

equals应当实现等价关系(equivalence relation):

  • 自反性(raflexive): 对于任何非null的引用x,x.equals(x)必须返回true。
  • 对称性(symmetric): 对于任何非null的引用x和y,当且仅当x.equals(y)返回true时,y.equals(x)必须返回true。
  • 传递性(transitive): 对于任何非null的引用x,y和z,如果x.equals(y)返回true,且y.equals(z)返回true,那么x.equals(z)必须返回true。
  • 一致性(consistent): 对于任何非null的引用x和y,只要equals的比较操作在对象所用的信息没有被修改,多次调用x.equals(y)就会一致地返回true,或者一致地返回false。
高质量equals的诀窍

  1. 使用==操作符检查”参数是否为这个对象的引用”。如果是,则直接返回true。这只是一种性能优化,如果比较操作有可能很昂贵,就值得这么做。
  2. 使用instanceof检查参数是否为正确的类型。如果不是,则返回false。
  3. 把参数转换为正确的类型。
  4. 对该类的每个关键域,检查参数中的域是否与该对象中的域相匹配。如果这些测试全部成功,返回true;否则返回false。
    基本类型用==,对象用equals,float用Float.compare(),double用Double.compare()。
    有些对象引用域包含null可能是合法的,所以习惯用下面的比较方法:
(filed == null ? o.filed == null:field.equals(o.field))
四省吾身:它是否是自反的、对称的、传递的、一致的

**一些告诫**
  1. 覆盖equals时总要覆盖hashCode。
  2. 不要企图让equals方法过于智能
  3. 不要将equals声明中的Object对象替换为其他的类型,比如下面的代码:
//这个方法并没有覆盖Object.equals,而是重载了它
//建议使用@Overwrite注解防止这种错误
public boolean equals(MyClass o){
    ...
}

Tip9. 覆盖equals时总要覆盖hashCode


JavaSE6的Object规范

  1. 应用程序的执行期间,只要对象的equals方法的比较操作所用到的信息没有改变,那么对同一个对象调用多次,hashCode必须始终如一的返回同一个整数。
  2. 如果两个对象根据equals方法比较是相等的,那么调用任意一个对象的hashCode方法,必须返回同样的整数结果。
  3. 如果两个对象根据equals方法比较是不相等的,那么调用两个对象中任意一个对象的hashCode方法,则不一定要产生不同的整数结果。

如果没有覆盖hashCode而只覆盖了equals,则违反了上述第二条的约定。这样将会导致该类无法结合所有基于散列的集合一起工作,包括HashMap,HashSet和Hashtable。

Tip10. 始终要覆盖toString


请将toString覆盖,并返回简洁但信息丰富的,并且易于阅读的信息。

Tip11. 谨慎的覆盖clone


如果不能保证实现良好的clone方法,就不要去考虑覆盖它。
可以考虑用拷贝构造方法,或拷贝工厂来实现同样的功能。请参考C++中的拷贝构造函数。

Tip12. 考虑实现Comparable接口


  1. 与equals类似,但支持泛型,而且表明类具有内在的排序关系。
  2. 可以跟许多泛型算法,以及依赖于该接口的集合实现进行协作。
  3. 一旦编写的类具有非常明显的内在排序关系,比如按字母顺序、按数值排序,就应该坚决考虑实现该接口。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值