1. 程式人生 > >java 反射中的包裝類與基本資料型別

java 反射中的包裝類與基本資料型別

寫了個執行反射方法的函式,但是卻老出問題,搗鼓了下,原來是基本資料型別出了問題,

呼叫反射中的方法時,需要知道方法的引數型別,

Method getDeclaredMethod(String name, Class<?>... parameterTypes)

但是因為引數是可變型別,我們要單獨下一個執行反射類中方法的工具方法的時候,要用陣列來處理,就會出現自動裝箱問題,

比如我定義的函式test1(int i,String s),我要呼叫這個方法,invoke(obj,"test1",1,"hello"),程式自動將int型別的1包裝成Integer型別的1,就會出現找不到此方法的異常,

解決辦法

  • 1寫方法的時候將int寫成Integer型別,建議
  • 2需要將其轉換成基本包裝型別的Class

包裝類的定義下都有一個屬性TYPE,根據這個屬性有還是沒有,可以判斷出裝箱後的Class是否為包裝類的Class,

執行一個函式的前提是你知道它的引數型別是基本的還是包裝的,如果有包裝型別的引數,那就不需要處理,自動裝箱後變成包裝類的Class,如果引數中沒有包裝類,是引用類和基本資料型別,就需要將自動包裝的Class轉換為基本型別的Class,

下面的transferToPrime函式就起這個作用,(說明,如果是單獨的一條語句Method method=c.getDeclaredMethod(String name, Class<?>... parameterTypes),你就可以手動地寫成int.class,double.class,但是抽取成方法時,需要注意

//如果引數中有包裝類,將其轉換為基本型別,其他型別不變
	public Class transferToPrime(Class c, String fieldName) {

		Field[] fields = c.getDeclaredFields();
		for (int i = 0; i < fields.length; i++) {

			if (fields[i].getName().equals(fieldName)) {
				try {

					return (Class) fields[i].get(null);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		return c;

	}
	//執行方法
	public Object invoke(Object obj, String methodName, Object... args) {
		Class[] params = new Class[args.length];
		for (int i = 0; i < args.length; i++) {

			Class f = args[i].getClass();
			params[i] = f;
//			params[i] = transferToPrime(f, "TYPE");
			System.out.println(params[i]);
		}

		try {
			// 從父類和子類所有方法中找
			Method m = obj.getClass().getMethod(methodName, params);
			return m.invoke(obj, args);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	//執行方法
	public Object invoke(String className, String methodName, Object... args) {
		Object obj = null;
		try {

			obj = Class.forName(className).getDeclaredConstructor().newInstance();

			return invoke(obj, methodName, args);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

另外,jdk9只有已經把Class類的newInstance方法廢棄,雖然還可以用,推薦使用Class的getDeclaredConstructor的newInstance方法,呼叫類中的無參構造器來建立物件,這也就是無參構造器存在的意義啦.

迴圈獲取指定欄位包括父類的,如果沒有報異常:

public Field getField(Class clazz,String fieldName){
		Field field = null;
		for(Class clazz2 = clazz;clazz2 != Object.class;
				clazz2=clazz2.getSuperclass()){
			try {
				field = clazz2.getDeclaredField(fieldName);
			} catch (Exception e) {	}
		}
		return field;
	}

迴圈獲取方法,包括父類的,如果沒有,報錯

/**
	 * 迴圈遍歷當前類及父類的所有方法,尋找指定方法
	 * @param c要獲取的Class物件
	 * @param methodName方法名
	 * @param parameterTypesClass型別的可變引數
	 * @return
	 */
	public Method getMethod(Class c, String method, Class... parameterTypes) {
		for (; c != Object.class; c = c.getSuperclass()) {
			try {
				Method m = c.getDeclaredMethod(method, parameterTypes);
				return m;
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return null;
	}