3

我有一个名为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);
        }
}
4

9 回答 9

4

As the others say, the signature of the method you override must be exactly the same. When overriding methods, to make sure you are overriding, use the @Override annotation above the function, so IDEs like Eclipse will warn you if you changed the method.

This is what it would look like:

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

I would suggest to override hashCode() as well because when inserting items into lists, sets, hastables, etc... for equality (and performande) hashCode() is used (and sometimes equals() is not!)

So your final code would be:

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

@Override
public int hashCode(){
...Your code here...
}

More info at the javadoc

于 2010-04-23T12:42:41.103 回答
2

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

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

于 2010-04-23T12:32:58.187 回答
1

Javadoc声明您需要使用 object 作为参数覆盖 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;
    }
}
于 2010-04-23T12:29:58.567 回答
1

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

于 2010-04-23T12:33:33.150 回答
1

以下是我将如何去做:

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);
    }
}

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

Person当一个人在子类(即: , )中覆盖此方法时,Car必须使用完全相同的签名来定义它。换句话说,equals方法的参数必须是 type Object,方法实现必须向下转型。

于 2010-04-23T12:34:28.183 回答
1

您的 equals 方法应如下所示:

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

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

于 2010-04-23T12:36:09.593 回答
1

通常很难/不可能完全履行 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 注释让编译器帮助您解决这个问题。在你的情况下,你会提前得到一个编译错误,这会节省你一些时间。

于 2010-04-23T12:42:36.347 回答
0

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

public boolean equals(Object o)

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

顺便说一句,您还可以将字符串与以下内容进行比较equals()

return registration.equals(car.registration);
于 2010-04-23T12:36:55.317 回答
0

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

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

于 2010-04-23T12:37:01.440 回答