直接上代码在这里插入代码片
public class Main {
public static void main(String[] args) {
User u1 = new User("张三", null, 18);
User u2 = new User("张三", "87654321", 20);
Set<String> excludeFields = new HashSet<>();
// excludeFields.add(“password”);
Map<String, Object> diffFields = ObjectCompareUtil.compareFields(u1, u2, excludeFields);
if (diffFields == null) {
System.out.println(“两个对象相同”);
} else {
System.out.println(“两个对象不同,不同字段如下:”);
String diffFieldsStr = ObjectCompareUtil.outputDiffFields(diffFields, u1);
System.out.println(diffFieldsStr);
}
// 输出:
// 两个对象不同,不同字段如下:
// 【年龄】由 『18』 变为 『20』
}
static class User {
@FieldDisplayName("姓名")
private String name;
@FieldDisplayName("密码")
private String password;
@FieldDisplayName("年龄")
private int age;
public User(String name, String password, int age) {
this.name = name;
this.password = password;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FieldDisplayName {
String value();
}
public class ObjectCompareUtil {
/**
* 比较两个对象的所有字段是否相同,并返回不同的字段名和值(除了需要屏蔽的字段)
*
* @param obj1 对象1
* @param obj2 对象2
* @param excludeFields 需要屏蔽的字段名集合
* @return 如果不同,则返回包含不同字段名和值的Map对象;如果相同,则返回null
*/
public static Map<String, Object> compareFields(Object obj1, Object obj2, Set<String> excludeFields) {
if (obj1 == null || obj2 == null) {
return null;
}
Class<?> clazz = obj1.getClass();
Field[] fields = clazz.getDeclaredFields();
Map<String, Object> diffFields = null; // 用于存放不同的字段名和值
try {
for (Field field : fields) {
if (excludeFields != null && excludeFields.contains(field.getName())) {
continue; // 如果是需要屏蔽的字段,则直接跳过
}
field.setAccessible(true);
Object value1 = field.get(obj1);
Object value2 = field.get(obj2);
if (value1 == null && value2 == null) { // 如果两个对象都为null,那么认为它们相同,直接跳过该字段
continue;
}
if (value1 == null || !value1.equals(value2)) { // 如果不同时为null,并且值不相等,那么存储到diffFields中返回
if (diffFields == null) {
diffFields = new HashMap<>(); // 初始化diffFields
}
diffFields.put(field.getName(), value2); // 存入不同的字段名和值
}
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
return diffFields;
}
/**
* 输出不同字段的具体名称和值
*
* @param diffFields 不同的字段名和值
* @param obj1 对象1
* @return 不同字段的具体名称和值
*/
public static String outputDiffFields(Map<String, Object> diffFields, Object obj1) {
StringBuilder sb = new StringBuilder();
Class<?> clazz = obj1.getClass();
for (Map.Entry<String, Object> entry : diffFields.entrySet()) {
String fieldName = entry.getKey();
Object fieldValue = entry.getValue();
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
String fieldDisplayName = field.getAnnotation(FieldDisplayName.class).value(); // 获取字段的显示名称
sb.append("").append(fieldDisplayName).append(":由 ").append(field.get(obj1)).append(" 变为 ").append(fieldValue).append(";");
} catch (Exception e) {
e.printStackTrace();
}
}
return sb.toString();
}
}