科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件对象相等比较:深入equals方法(2)

对象相等比较:深入equals方法(2)

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

另外一个quick check是if(this==obj) return true;

作者:中国IT实验室 来源:中国IT实验室 2007年8月23日

关键字: equals方法

  • 评论
  • 分享微博
  • 分享邮件

另外一个quick check是if(this==obj) return true;


是否equals方法一定比较的两个对象就一定是要同一类型?上面我用了"通常",这也是绝大多数程序
员的愿望,但是有些特殊的情况,我们可以进行不同类型的比较,这并不违反规范。但这种特殊情况
是非常罕见的,一个不恰当的例子是,Integer类的equals可以和Sort做比较,比较它们的value是不
是同一数学值。(事实上JDK的API中并没有这样做,所以我才说是不恰当的例子)

在完成quick check以后,我们就要真正实现你认为的“相等”。对于如果实现对象相等,没有太高
的要求,比如你自己实现的“人”类,你可以认为只要name相同即认为它们是相等的,其它的sex,
ago都可以不考虑。这是不完全实现,但是如果是完全实现,即要求所有的属性都是相同的,那么如
何实现equals方法?

class Human{
 private String name;
 private int ago;
 private String sex;
        ....................
        public boolean equals(Object obj){
  quick check.......
  Human other = (Human)ojb;
  return this.name.equals(other.name)
   && this.ago == ohter.ago
   && this.sex.equals(other.sex);
 }
}

这是一个完全实现,但是,有时equals实现是在父类中实现,而要求被子类继承后equals能正确的工
作,这时你并不事实知道子类到底扩展了哪些属性,所以用上面的方法无法使equals得到完全实现。
一个好的方法是利用反射来对equals进行完全实现:

        public boolean equals(Object obj){
  quick check.......
  Class c = this.getClass();
  Filed[] fds = c.getDeclaredFields();
  for(Filed f:fds){
   if(!f.get(this).equals(f.get(obj)))
    return false;
  }
  return true;
 }
为了说明的方便,上明的实现省略了异常,这样的实现放在父类中,可以保证你的子类的equals可以按
你的愿望正确地工作。

关于equals方法的最后一点是:如果你要是自己重写(正确说应该是履盖)了equals方法,那同时就一
定要重写hashCode().为是规范,否则.............
我们还是看一下这个例子:

public final class PhoneNumber {
    private final int areaCode;
    private final int exchange;
    private final int extension;

    public PhoneNumber(int areaCode, int exchange, int extension) {
        rangeCheck(areaCode, 999, "area code");
        rangeCheck(exchange, 99999999, "exchange");
        rangeCheck(extension, 9999, "extension");
        this.areaCode = areaCode;
        this.exchange = exchange;
        this.extension = extension;
    }

    private static void rangeCheck(int arg, int max, String name) {
        if(arg < 0 || arg > max)
            throw new IllegalArgumentException(name + ": " + arg);
    }

    public boolean equals(Object o) {
        if(o == this)
            return true;
        if(!(o instanceof PhoneNumber))
            return false;
        PhoneNumber pn = (PhoneNumber)o;
        return pn.extension == extension && pn.exchange == exchange && pn.areaCode == areaCode;
    }
}

注意这个类是final的,所以这个equals实现没有什么问题。

我们来测试一下:

    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));
        System.out.println(hm.get(pn1));
        System.out.println(hm.get(pn));
    }
既然pn.equals(pn1),那么我put(pn,"I love you");后,get(pn1)这什么是null呢?
答案是因为它们的hashCode不一样,而hashMap就是以hashCode为主键的。

所以规范要求,如果两个对象进行equals比较时如果返回true,那么它们的hashcode要求返回相等的值。

查看本文来源
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章