如何用Apache Commons HashCodeBuilder排除子类指定字段?
问题原因
HashCodeBuilder.reflectionHashCode的排除字段列表仅作用于当前被反射的类(此处为Car),你传入的version是嵌套类TyreClass的字段,Car类中不存在该字段,因此排除列表无法对其生效。另外你的代码里carObject_2.setVersion(2);是笔误,应该是carObject_2.getTyre().setVersion(2);,否则无法编译。
解决方案
方案1:手动实现哈希码(推荐,可控性更强)
放弃反射,手动编写hashCode方法,明确指定需要参与哈希计算的字段,彻底避免反射的局限性:
// TyreClass的hashCode实现,排除id和version @Override public int hashCode() { return new HashCodeBuilder(17, 37) .append(radius) .append(colour) .append(width) .toHashCode(); } // Car的hashCode实现,排除id,直接调用TyreClass的自定义hashCode @Override public int hashCode() { return new HashCodeBuilder(17, 37) .append(modelYear) .append(color) .append(tyre) .toHashCode(); }
使用时直接调用对象的hashCode()方法即可,无需依赖反射:
int hashCode_1 = carObject_1.hashCode(); int hashCode_2 = carObject_2.hashCode();
方案2:自定义FieldFilter实现反射过滤
如果必须使用反射,可以通过自定义FieldFilter来递归过滤所有需要排除的字段,包括嵌套类的字段:
// 自定义字段过滤器,指定所有要排除的字段 FieldFilter excludeFilter = (field) -> { // 排除Car类的id字段 if (field.getDeclaringClass() == Car.class && field.getName().equals("id")) { return false; } // 排除TyreClass的id和version字段 if (field.getDeclaringClass() == TyreClass.class && (field.getName().equals("id") || field.getName().equals("version"))) { return false; } return true; }; // 调用带过滤器的重载方法,开启递归处理嵌套对象(第三个参数为true) int hashCode_1 = HashCodeBuilder.reflectionHashCode(17, 37, carObject_1, true, null, excludeFilter); int hashCode_2 = HashCodeBuilder.reflectionHashCode(17, 37, carObject_2, true, null, excludeFilter);
补充:关于@HashCodeExclude注解
如果你的Apache Commons Lang版本≥3.12,HashCodeBuilder可以识别@HashCodeExclude注解,但需要确保调用的是支持注解的重载方法,且递归处理嵌套对象时注解能被识别。不过相比自定义过滤器或手动实现,注解的灵活性较差,遇到嵌套场景容易出现预期外的问题。
内容的提问来源于stack exchange,提问作者user1416932
相关产品推荐
相关产品推荐

