业务需求,有时候我们会需要比较当前的实体类的值是否和数据库查出来的某一条数据相同。
最初我以为直接用List.contains就可以比较,但是!俺们实际操作一下。
// 介是实体类
public class Employee {
private Integer id;
private String name;
private String gender;
private Long localId;
public Employee(Integer id, String name, String gender, Long localId) {
this.id = id;
this.name = name;
this.gender = gender;
this.localId = localId;
}
}
// 介是测试
public static void main(String[] args) {
List<Employee> employeeList = new ArrayList<Employee>();
employeeList.add(new Employee(1, "野兽先辈", "男", 114514L));
employeeList.add(new Employee(2, "Van♂", "男", 55555L));
employeeList.add(new Employee(3, "油咖喱", "女", 1700000005L));
employeeList.add(new Employee(4, "秧歌思达", "男", 515151L));
Employee employee = new Employee(3, "油咖喱", "女", 1700000005L);
System.out.println(employeeList.contains(employee));
}
好家伙,实际的情况是,false,这么说是完全不同噢,但是我们对比造的数据,第三条应该是一毛一样的。所以这样使用肯定是不对的。
查询资料和dalao们整理的发现,contains里属性值是比较的地址而不是值。要符合业务要求,就得在实体类中重写equals方法。但是,重写equals方法同时也必须重写hash,一套流程下来属实麻烦。所以自己试着写了个方法,只要部分匹配List的字段,我们就认为是相同的。
private static <T> boolean contains(final List<T> list, final Object ohter) throws IllegalAccessException {
Field[] aim = ohter.getClass().getDeclaredFields();
for (T t : list) {
Field[] fields = t.getClass().getDeclaredFields();
int count = 0;
for (Field value : aim) {
if (!value.isAccessible()) {
value.setAccessible(true);
}
for (Field field : fields) {
if (!field.isAccessible()) {
field.setAccessible(true);
}
if (value.getName().equals(field.getName()) &&
Objects.equals(value.get(ohter), field.get(t))) {
count++;
}
}
if (count == aim.length) {
return true;
}
}
}
return false;
}
我们实验试试:
下面的方法就会返回true了,我们改改数据试试
很好,只要实体里的数据有一个不同,就会返回false。符合我们的预期。
因为在方法里是通过名称比较的,所以,哪怕不是一个类,只要属性名相同。都可以使用。
PS:其实真正使用并不需要那么复杂,只是为了做泛型才不得不去使用反射。如果就用一两次,我建议直接把实体写死,这样方法就会很干净整洁,满足需求。
希望有dalao指点,优化一下。
(重写!重写你打夜,很多时候业务规范,PO、VO不能有这些花里胡哨的东西,而要用List的contains就得在实体类里重写equals方法,所以为了避免就在调用的方法里这样写咯)