У меня есть следующий абстрактный Person
класс:
import java.util.Objects;
public abstract class Person {
protected String name;
protected int id;
public Person(String name, int id) {
this.name = name;
this.id = id;
}
public abstract String description();
@Override
public boolean equals(Object obj) {
if(this == obj) return true;
if(!(obj instanceof Person)) return false;
return Objects.equals(this.name, ((Person) obj).name) &&
this.id == ((Person) obj).id;
}
@Override
public int hashCode() {
return Objects.hash(this.name, this.id);
}
}
И теперь у меня есть подкласс Person
с именем Employee
:
import java.time.LocalDate;
import java.util.Objects;
public class Employee extends Person {
private double salary;
private LocalDate hireDay;
public Employee(String name, int id, double salary, int year, int month, int day) {
super(name, id);
this.salary = salary;
this.hireDay = LocalDate.of(year, month, day);
}
@Override
public String description() {
return "Employee with a salary of " + this.salary;
}
@Override
public int hashCode() {
return super.hashCode() + Objects.hash(this.salary,this.hireDay);
}
@Override
public boolean equals(Object obj) {
return super.equals(obj) &&
Double.compare(this.salary, ((Employee) obj).salary) == 0
&& Objects.equals(this.hireDay,((Employee)obj).hireDay);
}
Для реализации равнометод должным образом, он должен соответствовать следующему контракту.
Рефлексивный: x.equals (x) всегда True
Симметричный: x.equals (y) эквивалентен y.equals (x)
Транзитивно: x.equals (y) и y.equals (z) означает, что x.equals (z) имеет значение true
Когда я вызываю метод equals ()суперкласс внутри подкласса, я сначала гарантирую, что все сравниваемые объекты являются подклассами суперкласса.Эта проблема решает проблему сравнения смешанных типов и заботится о контракте, упомянутом выше.Мне больше не нужно использовать следующую реализацию equals:
@Override
public boolean equals(Object obj) {
if(this == obj) return true;
else if(obj == null || this.getClass() != obj.getClass()) return false;
Employee other = (Employee) obj;
return Objects.equals(this.name, other.name) &&
Double.compare(this.salary, other.salary) == 0 &&
Objects.equals(this.hireDay, other.hireDay);
}
А именно, мне больше не нужно явно проверять, принадлежит ли текущий объект (this
) к тому же классу, что и obj
из-заметод в суперклассе, который использует оператор instance of
.
Надежнее ли помещать эту реализацию в оператор равенства применительно к суперклассу или лучше использовать более явный тест в подклассе, используя метод getClass()
, чтобы соответствовать контракту??
В терминах метода hashCode () я хэширую поля частного экземпляра, специфичные для подкласса, и просто добавляю это к результату метода хеширования в суперклассе.Я не смог найти никакой документации, которая показывает, является ли это правильным способом для реализации функции hashCode () в целом или в иерархии наследования.Я видел код, в котором люди явно указали свои собственные хэш-функции.
Я извиняюсь, если мои вопросы слишком общие, но я старался их задавать, не слишком двусмысленно.
РЕДАКТИРОВАТЬ:
Я попросил Intellij реализовать метод equals и hashcode, и он решил использовать последнюю реализацию, которую я опубликовал выше.Тогда, при каких обстоятельствах я бы использовал instance of
в суперклассе?Будет ли это, когда я реализую метод окончательного равенства в суперклассе, например, сравнивая только объекты Person на основе идентификатора пользователя?