[转帖]类继承关系中实现equals方法的一个细节_Android, Python及开发编程讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  Android, Python及开发编程讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 3327 | 回复: 0   主题: [转帖]类继承关系中实现equals方法的一个细节        下一篇 
lusxingbao
注册用户
等级:少校
经验:1487
发帖:100
精华:0
注册:2012-11-12
状态:离线
发送短消息息给lusxingbao 加好友    发送短消息息给lusxingbao 发消息
发表于: IP:您无权察看 2012-11-13 16:12:54 | [全部帖] [楼主帖] 楼主

equals方法
        书上说,我们要比较两个对象是否相等的时候需要定义equals()和hashCode()两个方法。equals方法的完整签名是:equals(Object o). 定义equals方法的过程无非以下几个步骤:

1. 比较传进来的对象是否为空,如果空则返回false。

2. 比较传进来的对象类型是否相同,不同则返回false.

3. 再根据定义的对象比较每个字段是否相等,不等则返回false.

我们都知道,equals()方法意味着一种可传递和交换的对等关系,也就是说,假如A.equals(B)的结果为true的话,那么B.equals(A)的结果也是true.

     如果引入了类继承关系的时候,子类需要定义同样的方法时可以重用父类的方法,只针对自己的部分进行修改。但是在稍微不注意的情况下可能会打破前面的这种假定。

继承关系的一个实现
        在不考虑hashCode方法的情况下,下面是一个包含父类和子类的equals实现:

Java代码 

class BaseClass
{
      private int x;
      public BaseClass(int i)
      {
            x = i;
      }
      public boolean equals(Object rhs)
      {
            if(!(rhs instanceof rhs))
            return false;
            return x == ((BaseClass)rhs).x;
      }
}
class DerivedClass extends BaseClass
{
      private int y;
      public DerivedClass(int i, int j)
      {
            super(i);
            y = j;
      }
      public boolean equals(Object rhs)
      {
            if(!(rhs instanceof DerivedClass))
            return false;
            return super.equals(rhs) &&
            y == ((DerivedClass)rhs).y;
      }
}
public class EqualsWithInheritance
{
      public static void main(String[] args)
      {
            BaseClass a = new BaseClass(5);
            DerivedClass b = new DerivedClass(5, 8);
            DerivedClass c = new DerivedClass(5, 8);
            System.out.println("b.equals(c): " + b.equals(c));
            System.out.println("a.equals(b): " + a.equals(b));
            System.out.println("b.equals(a): " + b.equals(a));
      }
}


 如果我们运行上面的代码,会发现一个比较奇怪的结果:

Java代码 

b.equals(c): true
a.equals(b): true
b.equals(a): false


 既然我们前面a.equals(b)为true了,为什么后面b.equals(a)的结果反而成为了false呢?这样的实现肯定有问题,很明显,它打破了equals()的对等性。

问题分析
        如果我们仔细去看前面的代码实现的话,会发现问题很可能出现在父类和子类定义的equals()方法中。在父类中定义的equals方法子类中也定义了。所以当我们a.equals(b)调用的时候,因为a是父类创建的对象,所以执行的是父类里的equals方法,而b是子类的实例化对象,b.equals(a)执行的是子类中的equals方法。

     另外,还有一个问题就是instanceof。在java里面,instanceof表示测试它左边的对象是否为它右边类的实例。由于类的继承关系,我们可以说一个子类也是父类的实例。比如说,在java中,所有对象都是继承自Object,那么我们任意定义的一个类的实例对象调用instanceof Object返回的结果都为true.所以问题的根源就在于这个instanceof。

     再看我们的这个问题,我们本身的逻辑要求是父类的实例和子类的实例是不一样的,所以a.equals(b)和b.equals(a)都应该返回false.那么,现在问题就是,我们该用什么方法来比较父类和子类是不同的类型呢?查阅过文档之后,我们可以使用getClass()方法。这个方法表示返回该对象的运行时class。我们都知道,在jvm虚拟机中,每个类的详细类型信息会被定义在方法区中,并被多个线程所共享。这里将包括每个类的详细不同,比如说b是类DerivedClass实例化的对象,这样就可以实现他们的区分。

下面是修改后的实现代码:

Java代码 

class BaseClass
{
      private int x;
      public BaseClass(int i)
      {
            x = i;
      }
      public boolean equals(Object rhs)
      {
            if(rhs == null || getClass() != rhs.getClass())
            return false;
            return x == ((BaseClass)rhs).x;
      }
}
class DerivedClass extends BaseClass
{
      private int y;
      public DerivedClass(int i, int j)
      {
            super(i);
            y = j;
      }
      public boolean equals(Object rhs)
      {
            return super.equals(rhs) &&
            y == ((DerivedClass)rhs).y;
      }
}
public class EqualsWithInheritance
{
      public static void main(String[] args)
      {
            BaseClass a = new BaseClass(5);
            DerivedClass b = new DerivedClass(5, 8);
            DerivedClass c = new DerivedClass(5, 8);
            System.out.println("b.equals(c): " + b.equals(c));
            System.out.println("a.equals(b): " + a.equals(b));
            System.out.println("b.equals(a): " + b.equals(a));
      }
}


运行结果如下:

Java代码 

b.equals(c): true
a.equals(b): false
b.equals(a): false


 总结:
        对象的equals()方法在结合继承的关系时容易被搞混淆。重点就是根据我们逻辑定义,如果需要详细考虑父类和子类的差别的话,应该考虑object.getClass()而不是instanceof。




赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论