Java - 抽象类,equals()和两个子类

时间:2010-04-23 12:25:31

标签: java abstract-class subclass equals abstract

我有一个名为 Xpto 的抽象类和两个扩展它的子类,名为 Person Car 。我还有一个名为测试的类,其中包含main()和一个方法 foo(),用于验证两个人或汽车(或类的任何扩展Xpto的对象)是否为等于。因此,我在Person和Car类中重新定义了 equals()。当两个人姓名相同时,两个人是平等的,当他们有相同的登记时,两个车是相同的。

但是,当我在Test类中调用foo()时,我总是得到“false”。我理解为什么:在Xpto抽象类中没有重新定义equals()。那么......我如何在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);
        }
}

10 个答案:

答案 0 :(得分:4)

正如其他人所说,你覆盖的方法的签名必须完全相同。覆盖方法时,为了确保覆盖,请使用函数上方的@Override注释,因此如果您更改了方法,Eclipse之类的IDE会发出警告。

这就是它的样子:

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

我建议覆盖hashCode(),因为当将项目插入到列表,集合,hastables等中时......使用相等(和performande)hashCode()(有时equals()不是!)

所以你的最终代码是:

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

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

javadoc

的更多信息

答案 1 :(得分:2)

  

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

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

答案 2 :(得分:1)

您是否需要public boolean equals(Object o)作为两个类中的方法签名?

答案 3 :(得分: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;
    }
}

答案 4 :(得分:1)

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

答案 5 :(得分:1)

您的equals方法应如下所示:

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

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

答案 6 :(得分:1)

通常很难/不可能完全实现等于合同,并且层次结构中仍然有两个不同的类彼此相等,并且通常不会这样做。通常,equals方法测试该类是否相同(因此相同子类的两个实例将彼此相等,但两个不同子类的两个实例将不相同)。

但是,在您的情况下,可以在Xpto中实现等于,因为只有一个属性。显而易见的方法是在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注释让编译器帮助您解决这个问题。在你的情况下,你会早点得到一个编译错误,这会节省你一些时间。

答案 7 :(得分:0)

以下是我的意思:

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不需要定义这样的方法。

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

答案 8 :(得分:0)

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

public boolean equals(Object o)

然后将o投射到Person / Car并进行比较。

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

return registration.equals(car.registration);

答案 9 :(得分:0)

你的子类定义了equals(Person)或equals(Car),它们都不会像传递Xpto那样。如果你将它们声明为等于(Xpto),或者更好地等于(对象),这样它们就可以在集合中工作,那么你的问题就会消失。

注意,如果你用这种方式重新声明equals()方法,(1)你需要检查你传递的对象的类,因为你不能保证它们不再是汽车或人,而且( 2)你可能也想覆盖getHashCode(),特别是如果你决定使它们都为equals(Object),因为getHashCode()应该为两个相等的对象返回相同的哈希码。