我正在考虑为equals和hashCode创建一个反射辅助方法。
好消息是我不必担心我的equals或hashCode实现中缺少字段。 糟糕的是我猜表现。你怎么看待这个想法?请分享您的意见!
这是我的平等初稿:
public final class ReflectiveEqualsHelper {
public static boolean isEqual(final Object a, final Object b) {
if (!isTypeEqual(a, b)) {
return false;
}
Field[] fields = getFields(a);
Object valueA;
Object valueB;
String fieldName;
for (int i = 0; i < fields.length; i++) {
fieldName = fields[i].getName();
valueA = getValueByFieldName(a, fieldName);
valueB = getValueByFieldName(b, fieldName);
if (!compare(valueA, valueB)) {
return false;
}
}
return true;
}
@SuppressWarnings("rawtypes")
private static Field[] getFields(final Object o) {
Class clazz = o.getClass();
Field[] fields = clazz.getDeclaredFields();
return fields;
}
private static Field getField(final Object o, final String name) {
try {
Field field = o.getClass().getDeclaredField(name);
return field;
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
}
private static Object getValueByFieldName(final Object o, final String name) {
Field field = getField(o, name);
field.setAccessible(true);
try {
Object value = field.get(o);
field.setAccessible(false);
return value;
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
private static boolean areBothNull(final Object a, final Object b) {
return (a == null && b == null);
}
private static boolean isTypeEqual(final Object a, final Object b) {
if (areBothNull(a, b)) {
return false;
}
return a.getClass().equals(b.getClass());
}
private static boolean compare(final Object a, final Object b) {
if (a == null) {
return false;
} else if (b == null) {
return false;
}
return a.equals(b);
}
}
public class ReflectiveEqualsHelperTest {
@Test
public void testIsEqual() {
Vector a = new Vector(Long.valueOf(1L), 3L);
Vector b = new Vector(Long.valueOf(1L), 3L);
Vector c = new Vector(Long.valueOf(2L), 3L);
boolean testA = ReflectiveEqualsHelper.isEqual(a, b);
boolean testB = ReflectiveEqualsHelper.isEqual(a, c);
boolean testC = ReflectiveEqualsHelper.isEqual(b, c);
assertTrue(testA);
assertFalse(testB);
assertFalse(testC);
}
class Vector {
public static final int STATIC = 1;
private Long x;
private long y;
public Vector(Long x, long y) {
super();
this.x = x;
this.y = y;
}
public Long getX() {
return x;
}
public void setX(Long x) {
this.x = x;
}
public long getY() {
return y;
}
public void setY(long y) {
this.y = y;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((x == null) ? 0 : x.hashCode());
result = prime * result + (int) (y ^ (y >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
return ReflectiveEqualsHelper.isEqual(this, obj);
}
}
}
干杯,凯文
答案 0 :(得分:4)
查看EqualsBuilder中的Apache Commons及其reflectionEquals
方法。这个库还有HashCodeBuilder +许多其他有用的东西。
答案 1 :(得分:3)
我建议Guava's Objects.hashCode。例如:
public int hashCode() {
return Objects.hashCode(getX(), getY(), getZ());
}
Objects.equals
方法应该可以帮助您构建isEquals方法。
答案 2 :(得分:2)
这太贵了。这些方法比你想象的要频繁得多。不要这样做。而是使用像Eclipse,IntelliJ或Netbeans这样的有点像IDE,并让它们自动生成equals()
和hashCode()
。例如,在Eclipse中,你可以通过右键单击源代码中的某个地方&gt; 来源&gt;生成hashCode并等于。
答案 3 :(得分:2)
由于使用反射,性能肯定是一个大问题,但还有其他。
有时您不想使用所有字段。特别是对于自引用结构,这可能导致潜在的无限递归。
答案 4 :(得分:1)
由于性能问题,我改变主意使用反射方法。现在我正在使用Apache commons项目的EqualsBuilder
和HashCodeBuilder
实用程序(感谢您的建议和反馈),因为它们隐藏了方法的复杂性。为了快速生成#equals
和#hashCode
方法,我使用Fast Code Eclipse plugin和自定义代码模板:
<template type="EQUALS_AND_HASHCODE_METHOD">
<variation></variation>
<variation-field></variation-field>
<allow-multiple-variation></allow-multiple-variation>
<class-pattern></class-pattern>
<allowed-file-extensions>java</allowed-file-extensions>
<number-required-classes>1</number-required-classes>
<description>Generates the equals and hashCode method with EqualsBuilder and HashCodeBuilder</description>
<template-body>
<![CDATA[
@Override
public boolean equals(final Object obj) {
if (obj == null) {
return false;
}
if (obj == this) {
return true;
}
if (obj.getClass() != getClass()) {
return false;
}
${class_name} rhs = (${class_name}) obj;
return new EqualsBuilder().appendSuper(super.equals(obj))
#foreach ($field in ${fields})
.append(${field.name}, rhs.${field.name})
#end
.isEquals();
}
@Override
public int hashCode() {
return new HashCodeBuilder(17, 37).appendSuper(super.hashCode())
#foreach ($field in ${fields})
.append(${field.name})
#end
.toHashCode();
}
]]>
</template-body>
</template>
我正在使用快速代码插件,因为它能够抓取所选类的所有字段。但我对插件的可用性不满意。如果eclipse代码模板引擎能够做到这一点将会很好。如果有人知道类似的插件,请告诉我!
干杯,凯文