Effective Java学习笔记-对于所有对象都通用的方法

第8条:覆盖equals时请遵守通用约定

1.什么时候应该覆盖Object.equals呢?

         如果类具有自己特有的“逻辑相等”概念(不同于对象等同的概念),而且超类还没有覆盖equals以实现期望的行为,这时就需要覆盖equals方法。(“值类”,仅仅表示一个值的类,例如:Integer或者Date)

         ==与equals的区别:==比较的是内存中的地址,比较的是对象的句柄,对象等同;而equals()比较的是地址内的内容,比较的是对象,逻辑相同.

         有一种值类不需要覆盖equals方法,即实例受控确保“每个值之多值存在一个对象”,例如枚举类型,这样的类,逻辑相同与对象等同是一回事。

2.覆盖equals应该遵守的约定:

          1.自反性:x.equals(x)必须返回true;

          2.对称性:当且仅当x.equals(y)返回true时,y.equals(x)必须返回true;

          3.传递性:如果x.equals(y)返回true时,并且y.equals(z)也返回true,那么x.equals(z)必须返回true

          4.一致性:多次调用x.equals(y)会一致的返回true或者false;

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

3.我们无法在扩展可实例化类的同时,既增加新的值组件,同时又保留equals约定,如Point(x,y)--ColorPoint(x,y,color),这怎么办呢?

在equals方法中用getClass测试代替instanceof测试:

     @Override

      public boolean equals(Object o){

           if(o == null || o.getClass() != getClass())

                   return false;

          Point p = (Point) o;

          return p.x == x && p.y == y;

       }

getClass与instanceof的区别:

  getClass()返回的是运行时类型,和编译时声明的类型无关.例如:

  List obj = new ArrayList();
      String objName = obj.getClass().getName();  //返回java.util.ArrayList
  

    而 obj instanceof List 和 obj instanceof ArrayList 都会返回 true 了

4.检查equals是否编写的正确的窍门:

      1.使用==操作符检查”参数是否为这个对象的引用“;

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

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

      4.域比较顺序可能影响equals方法的性能,应该最先比较最有可能不一致的域,或者开销最低的域;

  5.覆盖equals时总要覆盖hashCode;不要试图让equals方法过于只能;不要讲equals声明中的Object对象替换为其他类型;

5.对于float域,使用Float.compare方法;对于double域,使用Double.compare方法;如果数组中每个元素都很重要,就可以使用Arrays。equals方法

第9条:覆盖equals时总要覆盖hashCode

第10条:始终要覆盖toString

1.当对象被传递给println,printf,字符串连接符(+)以及assert或者被调试器打印出来时,toString方法会被自动调用。

第11条:谨慎地覆盖clone

第12条:考虑实现Comparable接口

1. Comparable接口中唯一的方法compareTo,不但允许进行简单的等同性比较,而且允许执行顺序比较,它与equals方法具有相似的特征,还是个泛型。

2.Arrays.sort()方法采用的是模板方法模式,它的算法包括三个方法,其中一个为CompareTo(),所以如果想修改排序的顺序规则,可以实现Comparable接口,覆盖compareTo()方法;

依赖于比较关系的类包括TreeSet,TreeMap,Collections和Arrays,他们内部包含有搜索和排序算法;

3.如果你正在编写一个值类,它具有非常明显的内在排序关系,比如按字母顺序、按数值顺序或者按照年代顺序,那就应该坚决考虑实现这个接口。

4.compareTo方法,将这个对象与指定对象进行比较时,当对象小于、等于或者大于指定对象时,分别返回-1、0、1.如果由于指定对象的类型而无法与该对象进行比较,则抛出ClassCastException异常;

5.compareTo与equals不一致的地方:BigDecimal类的compareTo方法与equals不一致,如new BigDecimal("1.0")和new BigDecimal("1.00")通过equals方法比较不相等,但通过compareTo方法比较相等;TreeSet和TreeMap的排序采用的compareTo方法比较;HashMap采用equals方法比较;

6.如果一个域并没有实现Comparable接口,或者你需要使用一个非标准的排序关系,就可以使用一个显示的Comparator来代替,或者编写自己的Comparator来代替,或者使用已有的Comparator;

 public class CaseInsensitiveString implements Comparable<CaseInsensitiveString> {

    @Override
    public int compareTo(CaseInsensitiveString cis) {
        return String.CASE_INSENSITIVE_ORDER.compare(s, cis.s);
        return 0;
    }

7.比较整数型基本类型的域,可以使用关系操作符<和>,但Double.compare和Float.compare,而不用关系操作符

posted @ 2011-07-09 15:03  跳刀的兔子  阅读(789)  评论(0编辑  收藏  举报