【问题标题】:Java - abstract class, equals(), and two subclassesJava - 抽象类、equals() 和两个子类
【发布时间】:2010-04-23 12:25:30
【问题描述】:

我有一个名为 Xpto 的抽象类和两个扩展它的子类,分别名为 PersonCar。我还有一个名为 Test 的类,它带有 main() 和一个方法 foo(),用于验证两个人或汽车(或扩展 Xpto 的类的任何对象)是否是等于。因此,我在 Person 和 Car 类中重新定义了 equals()。两个人同名时相等,两辆车同名时相等。

但是,当我在 Test 类中调用 foo() 时,我总是得到“假”。我明白为什么:equals() 没有在 Xpto 抽象类中重新定义。那么...如何在 foo() 方法中比较两个人或汽车(或扩展 Xpto 的类的任何对象)?

总而言之,这是我的代码:

public  abstract class Xpto {


}

public class Person extends Xpto{

        protected String name;

        public Person(String name){
                this.name = name;
        }

        public boolean equals(Person p){
                System.out.println("Person equals()?");
                return this.name.compareTo(p.name) == 0 ? true : false;
        }
}

public class Car extends Xpto{
        protected String registration;

        public Car(String registration){
                this.registration = registration;
        }

        public boolean equals(Car car){
                System.out.println("Car equals()?");
                return this.registration.compareTo(car.registration) == 0 ? true : false;
        }
}

public class Teste {

        public static void foo(Xpto xpto1, Xpto xpto2){
                if(xpto1.equals(xpto2))
                        System.out.println("xpto1.equals(xpto2) -> true");
                else
                        System.out.println("xpto1.equals(xpto2) -> false");

        }

        public static void main(String argv[]){
                Car c1 = new Car("ABC");
                Car c2 = new Car("DEF");
                Person p1 = new Person("Manel");
                Person p2 = new Person("Manel");

                foo(p1,p2);
        }
}

【问题讨论】:

    标签: java abstract-class subclass equals abstract


    【解决方案1】:

    正如其他人所说,您覆盖的方法的签名必须完全相同。重写方法时,为确保您正在重写,请在函数上方使用 @Override 注释,这样如果您更改了方法,Eclipse 等 IDE 会警告您。

    这就是它的样子:

    @Override
    public boolean equals(Object obj){
    ...Your code here...
    }
    

    我建议也覆盖hashCode(),因为在将项目插入列表、集合、hastables 等时...为了相等(和性能)使用hashCode()(有时equals() 不是!)

    所以你的最终代码是:

    @Override
    public boolean equals(Object obj){
    ...Your code here...
    }
    
    @Override
    public int hashCode(){
    ...Your code here...
    }
    

    更多信息请访问javadoc

    【讨论】:

    • 提到@Override 之前的第11 个答案。 叹息 +1
    【解决方案2】:

    我明白为什么:equals() 不是 在 Xpto 抽象类中重新定义。

    实际上equals() 没有在您的代码中任何地方重新定义。要覆盖它,您的方法必须将 Object 作为参数类型并且您必须对其进行强制转换(在使用 instanceof 进行测试后,在比较两个不同子类的实例时返回 false)。

    【讨论】:

      【解决方案3】:

      声明 public boolean equals(Person p) 或 public boolean equals(Car p) 不会覆盖 Object 的 public boolean equals(Object o),它只是一个永远不会调用的新方法。

      【讨论】:

        【解决方案4】:

        下面是我的做法:

        public  abstract class Xpto {
        
        }
        
        public class Person extends Xpto{
        
            protected String name;
        
            public Person(String name){
                    this.name = name;
            }
        
            public boolean equals(Object o){
               if(o == null || !getClass().equals(o.getClass())
                  return false;
               Person p = (Person) o;
               System.out.println("Person equals()?");
               return this.name.compareTo(p.name) == 0 ? true : false;
            }
        }
        
        public class Car extends Xpto {
            protected String registration;
        
            public Car(String registration){
                    this.registration = registration;
            }
        
            public boolean equals(Object o){
               if(o == null || !getClass().equals(o.getClass())
                  return false;
               Car car = (Car) o;
               System.out.println("Car equals()?");
               return this.registration.compareTo(car.registration) == 0 ? true : false;
            }
        }
        
        public class Teste {
        
            public static void foo(Xpto xpto1, Xpto xpto2){
                    if(xpto1.equals(xpto2))
                            System.out.println("xpto1.equals(xpto2) -> true");
                    else
                            System.out.println("xpto1.equals(xpto2) -> false");
        
            }
        
            public static void main(String argv[]){
                    Car c1 = new Car("ABC");
                    Car c2 = new Car("DEF");
                    Person p1 = new Person("Manel");
                    Person p2 = new Person("Manel");
        
                    foo(p1,p2);
            }
        }
        

        每个类都从Object 类继承equals(Object) 方法。因此,Xpto 不需要定义这样的方法。

        当在子类(即:PersonCar)中重写此方法时,必须使用完全相同的签名定义它。也就是说equals方法的参数必须是Object类型,方法实现必须向下转型。

        【讨论】:

        • getClass().equals(o.getClass()) 是抽象类的关键条件
        【解决方案5】:

        Javadoc 声明你需要重写以对象​​为参数的 equals 方法。

        表示是否有其他的对象 “等于”这个。

        因此,您的子类 equals 方法应如下所示:

        public class Car extends Xpto
        {
            protected String registration;
        
            public Car(String registration)
            {
                this.registration = registration;
            }
        
            public boolean equals(Object obj)
            {
                if (obj == null)
                {
                    return false;
                }
                if (obj == this)
                {
                    return true;
                }
                if (!obj.getClass().isAssignableFrom(getClass()))
                {
                    return false;
                }
                Car car = (Car) obj;
                return this.registration.compareTo(car.registration) == 0 ? true : false;
            }
        }
        

        【讨论】:

          【解决方案6】:

          完全履行equals契约并且在层次结构中仍然有两个不同的类彼此相等通常是非常困难/不可能的,并且通常不这样做。通常,equals 方法测试类是否相同(因此同一子类的两个实例将彼此相等,但两个不同子类的两个实例不相等)。

          但是,在您的情况下,可以在 Xpto 中实现 equals,因为只有一个属性。显而易见的方法是在 Xpto 中定义一个抽象方法,然后在 Xpto 中也覆盖 equals:

           public class Xpto {
                  protected abstract String getIdentity();
          
                  @Override
                  public boolean equals(Object o) {
                      if (o == null) return false;
                      //Typical implementation
                      //if (getClass() != o.getClass()) return false;
                      if (!(o instanceof Xpto)) return false; //risky implementation, but will allow a car to compare to a person
                       return getIdentity().equals((Xpto) o.getIdentity());
                  }
          
                  @Override
                  public int hashCode() {
                       return getIdentity().hashCode();
                  }
            }
          

          其他人指出您实际上并未在实现中覆盖 equals。将来,您可以使用 @Override 注释让编译器帮助您解决这个问题。在您的情况下,您会提前收到编译错误,这会节省您一些时间。

          【讨论】:

          • 哇,我们同时发布了相同的解决方案:P
          【解决方案7】:

          您的 equals 方法应如下所示:

          @Override public boolean equals(Object o) {
             if (!(o instanceof YourType)) {
                return false;
             }
             YourType yt = (YourType)o;
             ... // rest here
          }
          

          另外,不要忘记覆盖hashCode,以便能够在集合中正确使用您的类型。

          【讨论】:

            【解决方案8】:

            您没有覆盖equals() 方法,而是重载了它。将签名更改为

            public boolean equals(Object o)
            

            然后将 o 转换为 Person/Car 并进行比较。

            顺便说一句,您也可以将字符串与equals() 进行比较:

            return registration.equals(car.registration);
            

            【讨论】:

              【解决方案9】:

              您的子类定义了equals(Person) 或equals(Car),它们都不喜欢被传递Xpto。如果您将它们都声明为 equals(Xpto),或者更好的是 equals(Object),以便它们可以在集合中工作,那么您的问题应该会消失。

              注意,如果您以这种方式重新声明 equals() 方法,(1) 您需要检查您传递的对象的类,因为您不能再保证它们是 Cars 或 Persons,并且 ( 2) 你可能也想重写 getHashCode(),特别是如果你决定让它们都等于(Object),因为 getHashCode() 应该为两个相等的对象返回相等的哈希码。

              【讨论】:

                猜你喜欢
                • 2013-02-05
                • 1970-01-01
                • 1970-01-01
                • 2020-02-06
                • 2011-02-19
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多