(二十五)Java工具类EqualsBuilder协助Object.equals(object)方法详解
2018-02-09 17:15
507 查看
1.EqualsBuilder类基本简介
EqualsBuilder类提供方法为任何类建立良好的equals方法,它遵循Effective java定义的规则,特别是比较double、float、数组的大小是很棘手的,同时,确保equals()和hashcode()一致是很困难的。两个相等的对象必须生成相同的哈希代码,但是具有相同哈希代码的两个对象不一定相等。
所有的相关字段都应该包含在相等的计算中,派生字段可能被忽略,特别是任何字段生成哈希码都必须在equals方法中,反之亦然;
代码的典型用法如下:
public boolean equals(Object obj) { if (obj == null) { return false; } if (obj == this) { return true; } if (obj.getClass() != getClass()) { return false; } MyClass rhs = (MyClass) obj; return new EqualsBuilder() .appendSuper(super.equals(obj)) .append(field1, rhs.field1) .append(field2, rhs.field2) .append(field3, rhs.field3) .isEquals(); }
另外,有一种方法使用反射来确定要测试的字段。因为这些字段通常是私有的,方法是reflectionEquals,使用AccessibleObject.setAccessible方法改变字段的可见性,这将在安全管理器下失败,除非正确设置适当的权限,它也比测试明显慢很多,非原始数据类型使用equals比较;
这种方法的典型调用如下:
public boolean equals(Object obj) { return EqualsBuilder.reflectionEquals(this, obj); }
2.EqualsBuilder类源码详解
package org.apache.commons.lang3.builder; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.Collection; import java.util.HashSet; import java.util.Set; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ClassUtils; import org.apache.commons.lang3.tuple.Pair; /** * * 类描述 该类实现Builder<Boolean>接口,使用建造者模式增强equals方法 * * @param isEquals * */ public class EqualsBuilder implements Builder<Boolean> { private static final ThreadLocal<Set<Pair<IDKey, IDKey>>> REGISTRY = new ThreadLocal(); /** * * 方法描述 * * @param isEquals * */ static Set<Pair<IDKey, IDKey>> getRegistry() { return (Set)REGISTRY.get(); } /** * * 方法描述 * * @param isEquals * */ static Pair<IDKey, IDKey> getRegisterPair(Object lhs, Object rhs) { IDKey left = new IDKey(lhs); IDKey right = new IDKey(rhs); return Pair.of(left, right); } /** * * 方法描述 * * @param isEquals * */ static boolean isRegistered(Object lhs, Object rhs) { Set<Pair<IDKey, IDKey>> registry = getRegistry(); Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs); Pair<IDKey, IDKey> swappedPair = Pair.of(pair.getRight(), pair.getLeft()); return (registry != null) && ((registry.contains(pair)) || (registry.contains(swappedPair))); } /** * * 方法描述 * * @param isEquals * */ private static void register(Object lhs, Object rhs) { Set<Pair<IDKey, IDKey>> registry = getRegistry(); if (registry == null) { registry = new HashSet(); REGISTRY.set(registry); } Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs); registry.add(pair); } /** * * 方法描述 * * @param isEquals * */ private static void unregister(Object lhs, Object rhs) { Set<Pair<IDKey, IDKey>> registry = getRegistry(); if (registry != null) { Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs); registry.remove(pair); if (registry.isEmpty()) { REGISTRY.remove(); } } } private boolean isEquals = true; private boolean testTransients = false; private boolean testRecursive = false; private Class<?> reflectUpToClass = null; private String[] excludeFields = null; /** * * 方法描述 * * @param isEquals * */ public EqualsBuilder() {} /** * * 方法描述 * * @param isEquals * */ public EqualsBuilder setTestTransients(boolean testTransients) { this.testTransients = testTransients; return this; } /** * * 方法描述 * * @param isEquals * */ public EqualsBuilder setTestRecursive(boolean testRecursive) { this.testRecursive = testRecursive; return this; } /** * * 方法描述 * * @param isEquals * */ public EqualsBuilder setReflectUpToClass(Class<?> reflectUpToClass) { this.reflectUpToClass = reflectUpToClass; return this; } /** * * 方法描述 * * @param isEquals * */ public EqualsBuilder setExcludeFields(String... excludeFields) { this.excludeFields = excludeFields; return this; } /** * * 方法描述 * * @param isEquals * */ public static boolean reflectionEquals(Object lhs, Object rhs, Collection<String> excludeFields) { return reflectionEquals(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); } /** * * 方法描述 * * @param isEquals * */ public static boolean reflectionEquals(Object lhs, Object rhs, String... excludeFields) { return reflectionEquals(lhs, rhs, false, null, excludeFields); } /** * * 方法描述 * * @param isEquals * */ public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients) { return reflectionEquals(lhs, rhs, testTransients, null, new String[0]); } /** * * 方法描述 * * @param isEquals * */ public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients, Class<?> reflectUpToClass, String... excludeFields) { return reflectionEquals(lhs, rhs, testTransients, reflectUpToClass, false, excludeFields); } /** * * 方法描述 * * @param isEquals * */ public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients, Class<?> reflectUpToClass, boolean testRecursive, String... excludeFields) { if (lhs == rhs) { return true; } if ((lhs == null) || (rhs == null)) { return false; } return new EqualsBuilder().setExcludeFields(excludeFields).setReflectUpToClass(reflectUpToClass).setTestTransients(testTransients).setTestRecursive(testRecursive).reflectionAppend(lhs, rhs).isEquals(); } /** * * 方法描述 * * @param isEquals * */ public EqualsBuilder reflectionAppend(Object lhs, Object rhs) { if (!this.isEquals) { return this; } if (lhs == rhs) { return this; } if ((lhs == null) || (rhs == null)) { this.isEquals = false; return this; } Class<?> lhsClass = lhs.getClass(); Class<?> rhsClass = rhs.getClass(); if (lhsClass.isInstance(rhs)) { Class<?> testClass = lhsClass; if (!rhsClass.isInstance(lhs)) { testClass = rhsClass; } } else if (rhsClass.isInstance(lhs)) { Class<?> testClass = rhsClass; if (!lhsClass.isInstance(rhs)) { testClass = lhsClass; } } else { this.isEquals = false; return this; } try { Class<?> testClass; if (testClass.isArray()) { append(lhs, rhs); } else { reflectionAppend(lhs, rhs, testClass); while ((testClass.getSuperclass() != null) && (testClass != this.reflectUpToClass)) { testClass = testClass.getSuperclass(); reflectionAppend(lhs, rhs, testClass); } } } catch (IllegalArgumentException e) { this.isEquals = false; return this; } return this; } /** * * 方法描述 * * @param isEquals * */ private void reflectionAppend(Object lhs, Object rhs, Class<?> clazz) { if (isRegistered(lhs, rhs)) { return; } try { register(lhs, rhs); Field[] fields = clazz.getDeclaredFields(); AccessibleObject.setAccessible(fields, true); for (int i = 0; (i < fields.length) && (this.isEquals); i++) { Field f = fields[i]; if ((!ArrayUtils.contains(this.excludeFields, f.getName())) && (!f.getName().contains("$")) && ((this.testTransients) || (!Modifier.isTransient(f.getModifiers()))) && (!Modifier.isStatic(f.getModifiers())) && (!f.isAnnotationPresent(EqualsExclude.class))) { try { append(f.get(lhs), f.get(rhs)); } catch (IllegalAccessException e) { throw new InternalError("Unexpected IllegalAccessException"); } } } } finally { unregister(lhs, rhs); } } /** * * 方法描述 * * @param isEquals * */ public EqualsBuilder appendSuper(boolean superEquals) { if (!this.isEquals) { return this; } this.isEquals = superEquals; return this; } /** * * 方法描述 * * @param isEquals * */ public EqualsBuilder append(Object lhs, Object rhs) { if (!this.isEquals) { return this; } if (lhs == rhs) { return this; } if ((lhs == null) || (rhs == null)) { setEquals(false); return this; } Class<?> lhsClass = lhs.getClass(); if (!lhsClass.isArray()) { if ((this.testRecursive) && (!ClassUtils.isPrimitiveOrWrapper(lhsClass))) { reflectionAppend(lhs, rhs); } else { this.isEquals = lhs.equals(rhs); } } else { appendArray(lhs, rhs); } return this; } /** * * 方法描述 * * @param isEquals * */ private void appendArray(Object lhs, Object rhs) { if (lhs.getClass() != rhs.getClass()) { setEquals(false); } else if ((lhs instanceof long[])) { append((long[])lhs, (long[])rhs); } else if ((lhs instanceof int[])) { append((int[])lhs, (int[])rhs); } else if ((lhs instanceof short[])) { append((short[])lhs, (short[])rhs); } else if ((lhs instanceof char[])) { append((char[])lhs, (char[])rhs); } else if ((lhs instanceof byte[])) { append((byte[])lhs, (byte[])rhs); } else if ((lhs inst 10415 anceof double[])) { append((double[])lhs, (double[])rhs); } else if ((lhs instanceof float[])) { append((float[])lhs, (float[])rhs); } else if ((lhs instanceof boolean[])) { append((boolean[])lhs, (boolean[])rhs); } else { append((Object[])lhs, (Object[])rhs); } } /** * * 方法描述 * * @param isEquals * */ public EqualsBuilder append(long lhs, long rhs) { if (!this.isEquals) { return this; } this.isEquals = (lhs == rhs); return this; } /** * * 方法描述 * * @param isEquals * */ public EqualsBuilder append(int lhs, int rhs) { if (!this.isEquals) { return this; } this.isEquals = (lhs == rhs); return this; } /** * * 方法描述 * * @param isEquals * */ public EqualsBuilder append(short lhs, short rhs) { if (!this.isEquals) { return this; } this.isEquals = (lhs == rhs); return this; } /** * * 方法描述 * * @param isEquals * */ public EqualsBuilder append(char lhs, char rhs) { if (!this.isEquals) { return this; } this.isEquals = (lhs == rhs); return this; } /** * * 方法描述 * * @param isEquals * */ public EqualsBuilder append(byte lhs, byte rhs) { if (!this.isEquals) { return this; } this.isEquals = (lhs == rhs); return this; } /** * * 方法描述 * * @param isEquals * */ public EqualsBuilder append(double lhs, double rhs) { if (!this.isEquals) { return this; } return append(Double.doubleToLongBits(lhs), Double.doubleToLongBits(rhs)); } /** * * 方法描述 * * @param isEquals * */ public EqualsBuilder append(float lhs, float rhs) { if (!this.isEquals) { return this; } return append(Float.floatToIntBits(lhs), Float.floatToIntBits(rhs)); } /** * * 方法描述 * * @param isEquals * */ public EqualsBuilder append(boolean lhs, boolean rhs) { if (!this.isEquals) { return this; } this.isEquals = (lhs == rhs); return this; } /** * * 方法描述 * * @param isEquals * */ public EqualsBuilder append(Object[] lhs, Object[] rhs) { if (!this.isEquals) { return this; } if (lhs == rhs) { return this; } if ((lhs == null) || (rhs == null)) { setEquals(false); return this; } if (lhs.length != rhs.length) { setEquals(false); return this; } for (int i = 0; (i < lhs.length) && (this.isEquals); i++) { append(lhs[i], rhs[i]); } return this; } /** * * 方法描述 * * @param isEquals * */ public EqualsBuilder append(long[] lhs, long[] rhs) { if (!this.isEquals) { return this; } if (lhs == rhs) { return this; } if ((lhs == null) || (rhs == null)) { setEquals(false); return this; } if (lhs.length != rhs.length) { setEquals(false); return this; } for (int i = 0; (i < lhs.length) && (this.isEquals); i++) { append(lhs[i], rhs[i]); } return this; } /** * * 方法描述 * * @param isEquals * */ public EqualsBuilder append(int[] lhs, int[] rhs) { if (!this.isEquals) { return this; } if (lhs == rhs) { return this; } if ((lhs == null) || (rhs == null)) { setEquals(false); return this; } if (lhs.length != rhs.length) { setEquals(false); return this; } for (int i = 0; (i < lhs.length) && (this.isEquals); i++) { append(lhs[i], rhs[i]); } return this; } /** * * 方法描述 * * @param isEquals * */ public EqualsBuilder append(short[] lhs, short[] rhs) { if (!this.isEquals) { return this; } if (lhs == rhs) { return this; } if ((lhs == null) || (rhs == null)) { setEquals(false); return this; } if (lhs.length != rhs.length) { setEquals(false); return this; } for (int i = 0; (i < lhs.length) && (this.isEquals); i++) { append(lhs[i], rhs[i]); } return this; } /** * * 方法描述 * * @param isEquals * */ public EqualsBuilder append(char[] lhs, char[] rhs) { if (!this.isEquals) { return this; } if (lhs == rhs) { return this; } if ((lhs == null) || (rhs == null)) { setEquals(false); return this; } if (lhs.length != rhs.length) { setEquals(false); return this; } for (int i = 0; (i < lhs.length) && (this.isEquals); i++) { append(lhs[i], rhs[i]); } return this; } /** * * 方法描述 * * @param isEquals * */ public EqualsBuilder append(byte[] lhs, byte[] rhs) { if (!this.isEquals) { return this; } if (lhs == rhs) { return this; } if ((lhs == null) || (rhs == null)) { setEquals(false); return this; } if (lhs.length != rhs.length) { setEquals(false); return this; } for (int i = 0; (i < lhs.length) && (this.isEquals); i++) { append(lhs[i], rhs[i]); } return this; } /** * * 方法描述 * * @param isEquals * */ public EqualsBuilder append(double[] lhs, double[] rhs) { if (!this.isEquals) { return this; } if (lhs == rhs) { return this; } if ((lhs == null) || (rhs == null)) { setEquals(false); return this; } if (lhs.length != rhs.length) { setEquals(false); return this; } for (int i = 0; (i < lhs.length) && (this.isEquals); i++) { append(lhs[i], rhs[i]); } return this; } /** * * 方法描述 * * @param isEquals * */ public EqualsBuilder append(float[] lhs, float[] rhs) { if (!this.isEquals) { return this; } if (lhs == rhs) { return this; } if ((lhs == null) || (rhs == null)) { setEquals(false); return this; } if (lhs.length != rhs.length) { setEquals(false); return this; } for (int i = 0; (i < lhs.length) && (this.isEquals); i++) { append(lhs[i], rhs[i]); } return this; } /** * * 方法描述 * * @param isEquals * */ public EqualsBuilder append(boolean[] lhs, boolean[] rhs) { if (!this.isEquals) { return this; } if (lhs == rhs) { return this; } if ((lhs == null) || (rhs == null)) { setEquals(false); return this; } if (lhs.length != rhs.length) { setEquals(false); return this; } for (int i = 0; (i < lhs.length) && (this.isEquals); i++) { append(lhs[i], rhs[i]); } return this; } /** * * 方法描述 * * @param isEquals * */ public boolean isEquals() { return this.isEquals; } /** * * 方法描述 * * @param isEquals * */ public Boolean build() { return Boolean.valueOf(isEquals()); } /** * * 方法描述 * * @param isEquals * */ protected void setEquals(boolean isEquals) { this.isEquals = isEquals; } /** * * 方法描述 * * @param isEquals * */ public void reset() { this.isEquals = true; } }
相关文章推荐
- (二十五)Java工具类EqualsBuilder协助Object.equals(object)方法详解
- (二十五)Java工具类EqualsBuilder协助Object.equals(object)方法详解
- (二十五)Java工具类EqualsBuilder协助Object.equals(object)方法详解
- (二十五)Java工具类EqualsBuilder协助Object.equals(object)方法详解
- (二十五)Java工具类EqualsBuilder协助Object.equals(object)方法详解
- (二十五)Java工具类EqualsBuilder协助Object.equals(object)方法详解
- (二十五)Java工具类EqualsBuilder协助Object.equals(object)方法详解
- (二十五)Java工具类EqualsBuilder协助Object.equals(object)方法详解
- (二十五)Java工具类EqualsBuilder协助Object.equals(object)方法详解
- (二十五)Java工具类EqualsBuilder协助Object.equals(object)方法详解
- (二十五)Java工具类EqualsBuilder协助Object.equals(object)方法详解
- (二十五)Java工具类EqualsBuilder协助Object.equals(object)方法详解
- (二十五)Java工具类EqualsBuilder协助Object.equals(object)方法详解
- (二十五)Java工具类EqualsBuilder协助Object.equals(object)方法详解
- (二十五)Java工具类EqualsBuilder协助Object.equals(object)方法详解
- (二十五)Java工具类EqualsBuilder协助Object.equals(object)方法详解
- (二十五)Java工具类EqualsBuilder协助Object.equals(object)方法详解
- (二十五)Java工具类EqualsBuilder协助Object.equals(object)方法详解
- (二十五)Java工具类EqualsBuilder协助Object.equals(object)方法详解
- (二十五)Java工具类EqualsBuilder协助Object.equals(object)方法详解