2010-04-23 2 views
3

У меня есть абстрактный класс с именем Xpto и два подкласса, которые расширяют его называли Person и Автомобиля. У меня также есть класс Тест с main() и метод foo(), который проверяет, равны ли два человека или автомобили (или любой объект класса, который расширяет Xpto). Таким образом, я переопределил equals() в классах Person и Car. Два человека равны, когда они имеют одно и то же имя, а два автомобиля равны, когда они имеют одинаковую регистрацию.Java - абстрактный класс, равен(), и два подкласса

Однако, когда я вызываю foo() в классе Test, я всегда получаю «false». Я понимаю, почему: equals() не переопределяется в абстрактном классе Xpto. Итак ... как я могу сравнить двух человек или автомобили (или любой объект класса, который расширяет Xpto) в этом методе foo()?

В целом, это код у меня есть:

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

ответ

1

ли вам не нужно public boolean equals(Object o) как метод подписи в обоих классах?

1

В коде Javadoc указано, что вам необходимо переопределить метод 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; 
    } 
} 
2

Я понимаю, почему: равенства() не переопределен в Xpto абстрактного класса.

На самом деле equals() не переопределяется где-нибудь в вашем коде. Чтобы переопределить его, ваш метод должен иметь Object как тип параметра, и вы должны его использовать (после тестирования с instanceof для возврата false, когда сравниваются экземпляры двух разных подклассов).

1

Объявление public boolean equals (Person p) или public boolean equals (Car p) не переопределяет общедоступные логические значения Object (Object o), это просто новый метод, который никогда не вызывается.

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 не нужно определять такой метод.

При переопределении этого метода в подклассах (а именно: Person, Car) его необходимо определить с помощью той же самой сигнатуры. Другими словами, параметр метода equals должен иметь тип Object, а реализация метода должна понижать его.

1

Ваш метод равно должен выглядеть следующим образом:

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

Кроме того, не забудьте отменить hashCode, а также, чтобы иметь возможность правильно использовать свои типы в коллекциях.

0

Вы не переопределяете метод equals(), вместо этого перегружаете его. Изменить подпись на

public boolean equals(Object o) 

А затем бросить на человека/автомобиль и сделать сравнение.

И КСТАТИ, вы могли бы сравнить строки с equals(), а также:

return registration.equals(car.registration); 
0

Ваши подклассы определения равных (лицо) или равных (автомобиль), ни один из которых собирается нравится быть принят в Xpto. Если вы объявите их как равными (Xpto), или еще лучше, равно (Object), чтобы они работали в коллекциях, ваша проблема должна исчезнуть.

Обратите внимание, что если вы переопределите методы equals() таким образом, (1) вам нужно будет проверить классы объектов, которые вы передадите, поскольку вы не можете гарантировать, что они являются Автомобили или Лица, и (2) вы, вероятно, захотите также переопределить getHashCode(), особенно если вы решили сделать их равными (Object), потому что getHashCode() должен возвращать одинаковые хэш-коды для двух одинаковых объектов.

1

Как правило, очень сложно/невозможно полностью выполнить равный контракт и по-прежнему иметь два разных класса в иерархии, равные друг другу, и это, как правило, не выполняется. Как правило, тесты метода equals для класса одинаковы (так что два экземпляра одного и того же подкласса будут равны друг другу, но два экземпляра двух разных подклассов не будут).

Однако в вашем случае можно реализовать равные числа в Xpto, поскольку существует только одно свойство. Очевидный способ сделать это состоит в определении абстрактного метода в Xpto, а затем переопределить равно в Xpto, а также:

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

Другие указывали на то, что вы на самом деле не переопределяют равных в своей реализации. В будущем вы можете получить компилятор, чтобы помочь вам в этом, используя аннотацию @Override. В вашем случае вы наверняка получили бы ошибку компиляции, которая бы сэкономила вам некоторое время.

+0

Wow мы отправили такое же решение, в то же время: P – pakore

4

Как утверждают другие, подпись метода, который вы переопределяете, должна быть точно такой же. При переопределении методов, чтобы убедиться, что вы переопределяете, используйте надпись @Override над функцией, поэтому IDE, такие как Eclipse, будут предупреждать вас, если вы изменили метод.

Это то, что это будет выглядеть так:

@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

+0

Ответа номер 11, прежде чем '@ Override' упоминаются , * вздох * +1 –

 Смежные вопросы

  • Нет связанных вопросов^_^