1. 程式人生 > >java反射工具類--通過指定屬性名,獲取/設定物件屬性值

java反射工具類--通過指定屬性名,獲取/設定物件屬性值

java物件通過點運算子操作物件屬性的方式沒法使用for,while等迴圈,此工具主要解決這一問題.

例如:有一物件包含屬性有一定規律

obj1: {

    name1: "張三",
    age1: 1,

    name2: "李四",
    age2: 2,

    ....
}

要將此物件拆為多個小物件

objList:[

  {
         name: "張三",
         age: 1
  },
  {
         name: "李四",
         age: 2
  }
]

為了應對這種不能使用迴圈獲取屬性的情況,編寫了此工具類

核心實現程式碼如下:

/**
	 * @param o
	 *            操作物件
	 * @param methodName
	 *            方法名
	 * @param attName
	 *            屬性名
	 * @param value
	 *            值
	 * @return get方法返回實際值 set方法返回操作後物件
	 */
	private static Object Operation(Object o, String methodName, String attName, Class<?> paramType, Object value) {
		// 方法賦值出錯標誌
		boolean opErr = false;
		Object res = null;
		Class<?> type = o.getClass();
		try {
			Method method = null;
			if (methodName.indexOf("get") != -1) {
				// get方法
        // 獲取方法
				method = type.getMethod(methodName);
        // 執行
				res = method.invoke(o);
			} else {
				// set方法
        // 當沒有傳入引數型別時通過value獲取引數型別
				paramType = paramType == null ? value.getClass() : paramType;
        // 獲取方法
				method = type.getMethod(methodName, paramType);
        // 執行
				method.invoke(o, value);
				res = o;
			}
		} catch (Exception e) {
      // 通過get/set方法操作屬性失敗
			opErr = true;
			if (SHOW_LOG) {
				System.err.println(getThisName() + ": [WARN] 直接對屬性'" + attName + "進行操作(不借助get/set方法).");
			}
		}

		if (opErr) {
      // 通過打破封裝方式直接對值進行操作
			try {
				Field field = null;
        // 獲取屬性
				field = type.getDeclaredField(attName);
        // 打破封裝
				field.setAccessible(true);

				if (methodName.indexOf("get") != -1) {
        // get方法
        // 獲取屬性值
					res = field.get(o);
				} else {
        // set方法 
        // 設定屬性值
					field.set(o, value);
					res = o;
				}
			} catch (Exception e) {
				//兩種方法都操作失敗
				if (SHOW_LOG) {
					System.err.println(getThisName() + ": [ERROR] 屬性'" + attName + "'操作失敗.");
				}
			}
		}

		return res;
	}

set方法如下:

/**
	 * 設定屬性值
	 * 
	 * @param o
	 *            操作物件
	 * @param attName
	 *            屬性名
	 * @param value
	 *            引數值
	 * @param paramType
	 *            引數型別
	 * @return 操作後物件
	 */
	@SuppressWarnings("unchecked")
	public static <T> T set(T o, String attName, Object value, Class<?> paramType) {
		if (o == null || attName == null || attName.isEmpty()) {
			return null;
		}
		String methodName = attNameHandle("set", attName);

		return (T) Operation(o, methodName, attName, paramType, value);
	}

get方法如下:

/**
	 * 獲取屬性值
	 * 
	 * @param o
	 *            操作物件
	 * @param attName
	 *            屬性名
	 * @param returnType
	 *            返回值型別
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T get(Object o, String attName, Class<T> returnType) {
		if (o == null || attName == null || attName.isEmpty()) {
			return null;
		}
		String methodName = attNameHandle("get", attName);

		return (T) Operation(o, methodName, attName, null, null);
	}

通過屬性名獲取get/set方法名:

/**
     * 屬性名處理
     *
     * @param method
     *            方法(get/set)
     * @param attName
     * @return
     */
    private static String attNameHandle(String method, String attName) {
        StringBuffer res = new StringBuffer(method);
		// 屬性只有一個字母
        if (attName.length() == 1) {
            res.append(attName.toUpperCase());
        } else {
		// 屬性包含兩個字母及以上
            char[] charArray = attName.toCharArray();
    // 當前兩個字元為小寫時,將首字母轉換為大寫
            if (Character.isLowerCase(charArray[0]) && Character.isLowerCase(charArray[1])) {
                res.append(Character.toUpperCase(charArray[0]));
                res.append(attName.substring(1));
            } else {
                res.append(attName);
            }
        }
 
        return res.toString();
    }

完整程式碼:https://github.com/GFuZan/reflexTools


如果你現在在JAVA這條路上掙扎,也想在IT行業拿高薪,可以參加我們的訓練營課程,選擇最適合自己的課程學習,技術大牛親授,7個月後,進入名企拿高薪。我們的課程內容有:Java工程化、高效能及分散式、高效能、深入淺出。高架構。效能調優、Spring,MyBatis,Netty原始碼分析和大資料等多個知識點。如果你想拿高薪的,想學習的,想就業前景好的,想跟別人競爭能取得優勢的,想進阿里面試但擔心面試不過的,你都可以來,q群號為:856443934