弊端:
如果需要增減屬性,需要增減If-else代碼,會有代碼量大,不容易維護等問題。
解決方案:
那麼我們可以将屬性和值的映射成鍵值對,比較屬性的值是否相同來判斷值是否改動過。
由于未必是所有屬性比對,是以可以建立一個注解,允許隻比對帶有此注解的屬性。
如果兩個對象類型不同,隻比較其中兩個屬性,且屬性名不同怎麼辦?
那麼可以在注解上加上别名,這樣比對别名就好了。
上代碼(建議從github拉取):
github位址:
https://github.com/chujianyun/filed2valuepom檔案配置:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion>
<groupId>com.chujianyun</groupId>
<artifactId>field2hash</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
</dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<!--
https://mvnrepository.com/artifact/org.apache.commons/commons-lang3-->
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8.1</version>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
注解類:
package com.chujianyun.field2hash.annotation;
import java.lang.annotation.*;
/**
* 待校驗的屬性
* 允許指定别名
*
* @author [email protected]
* @date 2019年03月16日
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Field2Value {
String alias() default "";
}
package com.chujianyun.field2value.annotation;
* 需要忽略的屬性
* @date: 2019-04-08 10:15
public @interface Ignore {
工具類
package com.chujianyun.field2value.utils;
import com.chujianyun.field2value.annotation.Field2Value;
import com.chujianyun.field2value.annotation.Ignore;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
* 對象屬性名到其值的映射工具
* <p>
* 可用來比較值發生了變化的屬性
public class Field2ValueUtil {
/**
* 根據對象和屬性名+别名的集合擷取屬性集合
*
* @param object 待解析的對象
* @param fieldOrAliasNames 屬性名或者别名的集合
* @return 屬性集合
*/
public static Set<Field> getFieldsByFieldOrAliasNames(Object object, Set<String> fieldOrAliasNames) {
if (object == null || fieldOrAliasNames == null || fieldOrAliasNames.isEmpty()) {
return new HashSet<>(0);
}
Set<Field> fields2get = new HashSet<>(fieldOrAliasNames.size());
Class<?> clazz = object.getClass();
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
// 帶注解
if (field.isAnnotationPresent(Field2Value.class)) {
Field2Value annotation = field.getAnnotation(Field2Value.class);
String alias = annotation.alias();
if (fieldOrAliasNames.contains(alias) || fieldOrAliasNames.contains(field.getName())) {
fields2get.add(field);
break;
}
} else {
if (fieldOrAliasNames.contains(field.getName())) {
}
return fields2get;
}
* 根據屬性的名稱或者别名的名稱擷取屬性的值
* @param object 對象
* @param fieldNameOrAlias 屬性名或别名
* @return 該屬性的值
public static Object getValueByFieldNameOrAlias(Object object, String fieldNameOrAlias) throws IllegalAccessException {
Field field2resolve = null;
// 直接屬性名相同
if (field.getName().equals(fieldNameOrAlias)) {
field2resolve = field;
break;
// 别名相同
if (!"".equals(alias) && alias.equals(fieldNameOrAlias)) {
field2resolve = field;
if (field2resolve != null) {
field2resolve.setAccessible(true);
return field2resolve.get(object);
return null;
* 擷取兩個對象屬性的值不同的所有屬性名稱
* @param object1 第一個對象
* @param object2 第二個對象
* @param onlyCompareCommonFields 設計費
* @return 屬性的值不同的所有屬性名稱
public static Set<String> getDifferentValueFieldOrAliasNames(Object object1, Object object2, boolean resolveAllField, boolean onlyCompareCommonFields) throws IllegalAccessException {
Map<String, Object> field2ValuePair1 = getField2ValuePair(object1, resolveAllField);
Set<String> keySet1 = field2ValuePair1.keySet();
Map<String, Object> field2ValuePair2 = getField2ValuePair(object2, resolveAllField);
Set<String> keySet2 = field2ValuePair2.keySet();
if (keySet1.isEmpty()) {
return keySet2;
if (keySet2.isEmpty()) {
return keySet1;
Set<String> fieldsWithDifferentValue = new HashSet<>();
// 隻比較公共屬性
for (Map.Entry<String, Object> entry : field2ValuePair1.entrySet()) {
String fieldName = entry.getKey();
Object value1 = entry.getValue();
Object value2 = field2ValuePair2.get(fieldName);
boolean sameHashCode = (value1.hashCode() == value2.hashCode());
boolean sameObject = value1.equals(value2);
if (!(sameHashCode && sameObject)) {
fieldsWithDifferentValue.add(fieldName);
// 不相同的fields
if (!onlyCompareCommonFields) {
Set<String> keySet1Copy = new HashSet<>(keySet1);
Set<String> keySet2Copy = new HashSet<>(keySet2);
keySet1.removeAll(keySet2);
keySet2Copy.removeAll(keySet1Copy);
fieldsWithDifferentValue.addAll(keySet1);
fieldsWithDifferentValue.addAll(keySet2Copy);
return fieldsWithDifferentValue;
* 擷取屬性及其對應值得hash值(可能有hash沖突,謹慎使用)
* @param resolveAllField 解析所有屬性
* @return 屬性--> 值hash
public static <T> Map<String, Integer> getField2HashPair(T object, boolean resolveAllField) throws IllegalAccessException {
if (object == null) {
return new HashMap<>(0);
Map<String, Object> field2ValuePair = getField2ValuePair(object, resolveAllField);
Map<String, Integer> field2hashPairMap = new HashMap<>(field2ValuePair.size());
field2ValuePair.forEach((key, value) -> field2hashPairMap.put(key, value.hashCode()));
return field2hashPairMap;
* 擷取屬性及其對應值的映射(推薦使用)
* @return 屬性--> 值
public static <T> Map<String, Object> getField2ValuePair(T object, boolean resolveAllField) throws IllegalAccessException {
Map<String, Object> field2hashMap = new HashMap<>(declaredFields.length);
field.setAccessible(true);
String key = field.getName();
// 忽略的屬性
if (field.isAnnotationPresent(Ignore.class)) {
continue;
// 解析所有
if (resolveAllField) {
field2hashMap.put(key, field.get(object));
// 隻解析帶@Field2Value注解的
if (!"".equals(alias)) {
key = alias;
return field2hashMap;
實體類
package com.chujianyun.field2value;
import lombok.Data;
* Cat測試實體
@Data
public class Cat implements Cloneable {
private String name;
private Byte age;
@Field2Value(alias = "nick")
private String nickName;
@Field2Value
private String ownerName;
@Ignore
private String role;
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
測試類:
package com.chujianyun.field2hash.utils;
import com.chujianyun.field2hash.Cat;
import org.apache.commons.lang3.ObjectUtils;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
* Field2ValueUtil測試類
public class Field2ValueUtilTest {
private Cat cat = null;
private String age = "age";
@Before
public void init() {
// 原始屬性
cat = new Cat();
cat.setAge(Byte.parseByte("1"));
cat.setName("喵咪");
cat.setNickName("tomcat");
cat.setOwnerName("了凡");
@Test
public void filed2hashTest() throws IllegalAccessException {
Map<String, Integer> field2HashPair = Field2ValueUtil.getField2HashPair(cat, false);
System.out.println("修改前" + field2HashPair);
cat.setOwnerName("張無忌");
Map<String, Integer> field2HashPair2 = Field2ValueUtil.getField2HashPair(cat, false);
System.out.println("修改後" + field2HashPair2);
* 擷取屬性值不同的屬性名
public void getDifferentValueFieldNames() throws IllegalAccessException {
Cat catClone = ObjectUtils.clone(cat);
catClone.setOwnerName("張無忌");
// 兩個對象不同的屬性名活别名集合
Set<String> differentValueFieldOrAliaNames = Field2ValueUtil.getDifferentValueFieldOrAliasNames(cat, catClone, false, true);
System.out.println(differentValueFieldOrAliaNames);
assertEquals(differentValueFieldOrAliaNames.size(), 1);
// 屬性名或别名集合
for (String fieldNameOrAlias : differentValueFieldOrAliaNames) {
System.out.println(Field2ValueUtil.getValueByFieldNameOrAlias(catClone, fieldNameOrAlias));
// 屬性集合
Set<Field> fieldsByFieldOrAliasNames = Field2ValueUtil.getFieldsByFieldOrAliasNames(catClone, differentValueFieldOrAliaNames);
System.out.println(fieldsByFieldOrAliasNames);
* 解析待注解的屬性
public void getField2HashPair() throws IllegalAccessException {
Map<String, Integer> field2HashPair1 = Field2ValueUtil.getField2HashPair(cat, false);
System.out.println(field2HashPair1);
assertNull(field2HashPair1.get(age));
* 解析所有屬性
public void getField2HashPairAllFields() throws IllegalAccessException {
Map<String, Integer> field2HashPair = Field2ValueUtil.getField2HashPair(cat, true);
System.out.println(field2HashPair);
assertNotEquals(field2HashPair.get(age), "1");
————————————————
版權聲明:本文為CSDN部落客「明明如月學長」的原創文章,遵循CC 4.0 BY-SA版權協定,轉載請附上原文出處連結及本聲明。
原文連結:
https://blog.csdn.net/w605283073/article/details/88606762