Java中equals()与hashCode()方法详解

http://bijian1013.iteye.com/blog/1972404

1.对于任何引用类型, o.equals(o) == true成立.
2.如果 o.equals(o1) == true 成立,那么o1.equals(o)==true也一定要成立.
3.如果 o.equals(o1) == true 成立且  o.equals(o2) == true 成立,那么
  o1.equals(o2) == true 也成立.
4.如果第一次调用o.equals(o1) == true成立再o和o1没有改变的情况下以后的任何次调用
都成立.
5.o.equals(null) == true 任何时间都不成立.

对于类fieldpostion中的equal方法

    public boolean equals(Object obj) {
        if (obj == null)
            return false;
        if (!(obj instanceof FieldPosition))// 会出现问题,对于子类与父类比较时,始终是true,不会进行短路
            return false;
        FieldPosition other = (FieldPosition) obj;
        if (attribute == null) {
            if (other.attribute != null) {
                return false;
            }
        } else if (!attribute.equals(other.attribute)) {
            return false;
        }
        return (beginIndex == other.beginIndex && endIndex == other.endIndex && field == other.field);
    

例如:

class MyTest extends FieldPosition {
    int x = 10;

    public MyTest(int x) {
        super(x);
        this.x = x;
    }

    /**
     * 在实现equals方法 时都用过instanceof运行符来进行短路优化的 而有些稍有了解的程序员可能知道这样的优化可能
     * 有些不对但找不出问题的关键。另外一种极端是知道这个技术缺陷的骨灰级专家就提议不要这 样应用。
     * 我们知道,"通常"要对两个对象进行比较,那么它们"应该"是同一类型。所以首先利用instanceof
     * 运行符进行短路优化,如果被比较的对象不和当前对象是同一类型则不用比较返回false,但事实 上,"子类是父类的一个实例",所以如果 子类 o
     * instanceof 父类,始终返回true,这时肯定 不会发生短路优化,
     */
    public boolean equals(Object o) {
        if (o == null)
            return false;
        if (getClass() != o.getClass())
            return false;
        return ((MyTest) o).x == this.x;
    }
}

public class EqualTrack {
    public static void main(String[] args) {
        FieldPosition fp = new FieldPosition(10);
        FieldPosition fp1 = new MyTest(10);
        System.out.println(fp.equals(fp1));// true,此处应该为false,由于jdk中出现instance短路问题:子类始终未父类的实例,对final类可以使用instance短路用法

        System.out.println(fp1.equals(fp));// false
    }
}

两个对象,出现了不对称的equals算法..问题出在jdk源码

if (!(obj instanceof FieldPosition))// 会出现问题,对于子类与父类比较时,始终是true,不会进行短路
            return false;

我们知道,"通常"要对两个对象进行比较,那么它们"应该"是同一类型。所以首先利用instanceof
运行符进行短路优化,如果被比较的对象不和当前对象是同一类型则不用比较返回false,但事实
上,"子类是父类的一个实例",所以如果 子类 o instanceof 父类,始终返回true,这时肯定
不会发生短路优化,下面的比较有可能出现多种情况,一种是不能造型成子类而抛出异常,另一种
是父类的private 成员没有被子类继承而不能进行比较,还有就是形成上面这种不对称比较。可能
会出现太多的情况。

正确实现equal hashcode方法

package netease;

public class Human {
    private int age;

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        // 不能用obj instanceof 来比较,在子类中会出现问题
        if (this.getClass() != obj.getClass())
            return false;
        Human other = (Human) obj;
        if (age != other.age)
            return false;
        return true;
    }

}

当只实现equal不实现hashcode方法时,可能会导致相同对象添加到容器中,因为hashcode是根据内存地址生成,不重写hashcode方法,不同对象的hashcode值肯定不相同

  public static void main(String[] args) {
        Map hm = new HashMap();
        PhoneNumber pn = new PhoneNumber(123, 38942, 230);
        hm.put(pn, "I love you");
        PhoneNumber pn1 = new PhoneNumber(123, 38942, 230);
        System.out.println(pn);
        System.out.println("pn.equals(pn1) is " + pn.equals(pn1));//只重写了equals方法,没有重写hashcode,获取对象的hashcode时仍然根据object的hashcode方法                                       //获取,object的hashcode根据内存地址生成,导致pn1和pn的hashcode肯定不相同
        System.out.println(hm.get(pn1));//pn和pn1的hashcode不相同
        System.out.println(hm.get(pn));//
    }

 

posted @ 2016-03-21 21:10  程序猿进化之路  阅读(167)  评论(0)    收藏  举报