有時候業務須要,需記錄一條記錄的修改歷史,可是不能爲完成任務而硬編碼,不靠譜html
這種狀況能夠使用java反射來完成java
對對象屬性的描述能夠經過自定義註解來完成,讀取裏面的屬性進而記錄修改歷史。git
在對象的屬性上面加上註解,value設置爲屬性的中文描述github
工具了代碼以下數組
util類(BeanChangeUtil)app
import java.beans.PropertyDescriptor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Arrays; public class BeanChangeUtil<T> { public String contrastObj(Object oldBean, Object newBean) { // 建立字符串拼接對象 StringBuilder str = new StringBuilder(); // 轉換爲傳入的泛型T T pojo1 = (T) oldBean; T pojo2 = (T) newBean; // 經過反射獲取類的Class對象 Class clazz = pojo1.getClass(); // 獲取類型及字段屬性 Field[] fields = clazz.getDeclaredFields(); return jdk8Before(fields, pojo1, pojo2, str,clazz); // return jdk8OrAfter(fields, pojo1, pojo2, str,clazz); } // jdk8 普通循環方式 public String jdk8Before(Field[] fields,T pojo1,T pojo2,StringBuilder str,Class clazz){ int i = 1; try { for (Field field : fields) { if(field.isAnnotationPresent(PropertyMsg.class)){ PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz); // 獲取對應屬性值 Method getMethod = pd.getReadMethod(); Object o1 = getMethod.invoke(pojo1); Object o2 = getMethod.invoke(pojo2); if (o1 == null || o2 == null) { continue; } if (!o1.toString().equals(o2.toString())) { str.append(i + "、" + field.getAnnotation(PropertyMsg.class).value() + ":" + "修改前=>" + o1 + ",修改後=>" + o2 + "\n"); i++; } } } } catch (Exception e) { e.printStackTrace(); } return str.toString(); } // lambda表達式,表達式內部的變量都是final修飾,須要傳入須要傳入final類型的數組 public String jdk8OrAfter(Field[] fields, T pojo1, T pojo2, StringBuilder str, Class clazz){ final int[] i = {1}; Arrays.asList(fields).forEach(f -> { if(f.isAnnotationPresent(PropertyMsg.class)){ try { PropertyDescriptor pd = new PropertyDescriptor(f.getName(), clazz); // 獲取對應屬性值 Method getMethod = pd.getReadMethod(); Object o1 = getMethod.invoke(pojo1); Object o2 = getMethod.invoke(pojo2); if (o1 == null || o2 == null) { return; } if (!o1.toString().equals(o2.toString())) { str.append(i[0] + "、" + f.getAnnotation(PropertyMsg.class).value() + ":" + "修改前=>" + o1 + "\t修改後=>" + o2 + "\n"); i[0]++; } }catch (Exception e){ e.printStackTrace(); } } }); return str.toString(); } }
自定義註解(PropertyMsg)工具
@Targetui
表示該註解能夠用於什麼地方,可能的ElementType參數有:this
CONSTRUCTOR:構造器的聲明編碼
FIELD:域聲明(包括enum實例)
LOCAL_VARIABLE:局部變量聲明
METHOD:方法聲明
PACKAGE:包聲明
PARAMETER:參數聲明
TYPE:類、接口(包括註解類型)或enum聲明
@Retention
表示須要在什麼級別保存該註解信息。可選的RetentionPolicy參數包括:
SOURCE:註解將被編譯器丟棄
CLASS:註解在class文件中可用,但會被VM丟棄
RUNTIME:VM將在運行期間保留註解,所以能夠經過反射機制讀取註解的信息。
@Document
將註解包含在Javadoc中
@Inherited
容許子類繼承父類中的註解
import java.lang.annotation.*; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface PropertyMsg { String value(); }
使用方式test
public class TestChange { public static void main(String[] args) { TestChange u1 = new TestChange("我是誰", "ok", 30,"劉德華"); TestChange u2 = new TestChange("我在哪", "no", 20,"郭富城"); BeanChangeUtil<TestChange> t = new BeanChangeUtil<>(); String str = t.contrastObj(u1, u2); if (str.equals("")) { System.out.println("未有改變"); } else { System.out.println(str); } } public TestChange() { } public TestChange(String about, String lock, Integer age, String name) { this.about = about; this.lock = lock; this.age = age; this.name = name; } @PropertyMsg("關於") private String about; private String lock; @PropertyMsg("年齡") private Integer age; @PropertyMsg("姓名") private String name; get... set... 省略 }
OK,到位
https://github.com/chywx/JavaSE_chy
原文出處:https://www.cnblogs.com/chywx/p/10634547.html