В ответ на ответ Джона Скита я недавно столкнулся с ситуацией, когда мне нужно было реализовать метод hashCode только с подмножеством полей, используемых в методе equals. Сценарий (упрощенного) заключается в следующем:
У меня есть два класса A
и B
, каждый из которых содержит ссылку на другую в дополнение к определению строкового ключа. Использование автоматического хэш-код и составляет генератор в Eclipse (который, в отличие от Netbeans, только дает возможность использовать одни и те же поля в обоих методах) я в конечном итоге со следующими классами:
public class A {
public B b;
public String bKey;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((b == null) ? 0 : b.hashCode());
result = prime * result + ((bKey == null) ? 0 : bKey.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof A))
return false;
A other = (A) obj;
if (b == null) {
if (other.b != null)
return false;
} else if (!b.equals(other.b))
return false;
if (bKey == null) {
if (other.bKey != null)
return false;
} else if (!bKey.equals(other.bKey))
return false;
return true;
}
}
public class B {
public A a;
public String aKey;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((a == null) ? 0 : a.hashCode());
result = prime * result + ((aKey == null) ? 0 : aKey.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof B))
return false;
B other = (B) obj;
if (a == null) {
if (other.a != null)
return false;
} else if (!a.equals(other.a))
return false;
if (aKey == null) {
if (other.aKey != null)
return false;
} else if (!aKey.equals(other.aKey))
return false;
return true;
}
}
Проблема возникла, когда я попытался чтобы добавить класс А к HashSet следующим образом:
public static void main(String[] args) {
A a = new A();
B b = new B();
a.b = b;
b.a = a;
Set<A> aSet = new HashSet<A>();
aSet.add(a);
}
Это закончится в StackOverflowError, так как при добавлении a
к aSet
приведет к a
«методе HashCode с называют, что приведет к b
» ы hashCode
быть который будет r esult в a
hashCode
, вызываемый и т. д. и т. д. и т. д.Единственный способ обойти это - либо удалить ссылку на A
от B
's hashCode
и equals
ИЛИ включить только String bKey
в метод hashCode B
. Поскольку я хотел, чтобы метод B.equals
включал ссылку A в проверку равенства, единственное, что я мог сделать, это сделать только то, что было использовано в B.equals
, но только B.bKey
в B.hashCode
. Я не видел другого пути.
Возможно, мой дизайн ошибочен, и я приветствую кого-то, чтобы указать на это, но это, по сути, то, как мои объекты домена структурированы в моей реальной программе.
С учетом того, что генератор кода Netbeans ошибочен, чтобы дать выбор, если нет веской причины выбирать разные поля. – Raedwald