pracuję nad projektem, gdzie wiele klas potrzebują odpowiedniego typowe implementacje equals
i hashCode
: każda klasa ma zestaw końcowych pól zainicjowany w budownictwie z „głęboko” niezmiennych obiektów (null
s są przeznaczone do zaakceptowania w niektórych przypadkach) do wykorzystania do mieszania i porównywania.wielokrotnego użytku realizacja równych i hashcode
Aby zmniejszyć ilość kodu standardowego, pomyślałem o napisaniu klasy abstrakcyjnej zapewniającej powszechne implementacje takiego zachowania.
public abstract class AbstractHashable {
/** List of fields used for comparison. */
private final Object[] fields;
/** Precomputed hash. */
private final int hash;
/**
* Constructor to be invoked by subclasses.
* @param fields list of fields used for comparison between objects of this
* class, they must be in constant number for each class
*/
protected AbstractHashable(Object... fields) {
this.fields = fields;
hash = 31 * getClass().hashCode() + Objects.hash(fields);
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj == null || !getClass().equals(obj.getClass())) {
return false;
}
AbstractHashable other = (AbstractHashable) obj;
if (fields.length != other.fields.length) {
throw new UnsupportedOperationException(
"objects of same class must have the same number of fields");
}
for (int i=0; i<fields.length; i++) {
if (!fields[i].equals(other.fields[i])) {
return false;
}
}
return true;
}
@Override
public int hashCode() {
return hash;
}
}
ten ma być stosowany tak:
public class SomeObject extends AbstractHashable {
// both Foo and Bar have no mutable state
private final Foo foo;
private final Bar bar;
public SomeObject(Foo foo, Bar bar) {
super(foo, bar);
this.foo = Objects.requireNonNull(foo);
this.bar = bar; // null supported
}
// other methods, no equals or hashCode needed
}
To jest w zasadzie to, co zaproponował here z pewnymi różnicami.
To wydaje mi się proste, ale dobre podejście do zmniejszenia gadatliwości i nadal mają skuteczne wdrożenia equals
i hashCode
. Jednakże, ponieważ nie przypominam sobie, aby kiedykolwiek widziałem coś podobnego (z wyjątkiem odpowiedzi powiązanej powyżej), chciałbym zapytać konkretnie, czy jest jakiś punkt przeciwko takiemu podejściu (lub ewentualnie pewnej poprawie, którą można by zastosować), przed zastosowaniem w całym projekcie.
Widzę już dwie kwestie. 1. Dwa obiekty będą traktowane jednakowo, jeśli * wszystkie * ich pola będą zgodne. To nie zawsze może być to, czego chcesz. 2. Klasa może rozszerzyć tylko o jedną klasę. Czy naprawdę chcesz zablokować swoje klasy z dziedziczenia innych klas, ponieważ ponowne użycie 'hash' i' hashCode' jest ważniejsze? – CKing