Java的反射

Java的反射

Class類

在此以前,咱們必須知道一句話,「java之中的一切均可以看做一個對象」。類是對象的抽象,而Class則是類的抽象,即任何一個類都是Class的實例對象。另外注意區別Class類和class關鍵字。Class類下面有不少方法,例如getConstructors() (包括其一些類似做用的方法這裏以及後面再也不列舉,例如getDeclaredConstructor()等等),getFields(),getMethods();而它們會分別返回Constructor類型、Filed類型、Method類型的對象或者數組。Class類的構造方法是私有的,當一個類被加載時,JVM(java虛擬機)會自動經過Class的私有構造方法實例化一個Class對象,而咱們沒有辦法經過Class的構造方法去實例化Class。而咱們能夠經過如下三種方法來得到Class的實例化對象;java

  1. 類名.forName("具體路徑 包名.類名");
  2. 類名.class;
  3. 對象.getClass();

得到了Class的實例化對象,咱們就能夠得到類的不少信息,例如權限修飾符,參數列表,類名,成員變量,成員方法等等。程序員

問:什麼是Java的反射?

答:你們都知道,要讓Java程序可以運行,那麼就得讓Java類要被Java虛擬機加載。Java類若是不被Java虛擬機加載,是不能正常運行的。如今咱們運行的全部的程序都是在編譯期的時候就已經知道了你所須要的那個類的已經被加載了。

Java的反射機制是在編譯並不肯定是哪一個類被加載了,而是在程序運行的時候才加載、探知、自審。使用在編譯期並不知道的類。這樣的特色就是反射。數組

問:Java反射有什麼做用呢?

答:假如咱們有兩個程序員,一個程序員在寫程序的時候,須要使用第二個程序員所寫的類,但第二個程序員並沒完成他所寫的類。那麼第一個程序員的代碼可否經過編譯呢?這是不能經過編譯的。利用Java反射的機制,就可讓第一個程序員在沒有獲得第二個程序員所寫的類的時候,來完成自身代碼的編譯。

Java的反射機制它知道類的基本結構,這種對Java類結構探知的能力,咱們稱爲Java類的「自審」。你們都用過Jcreator和eclipse。當咱們構建出一個對象的時候,去調用該對象的方法和屬性的時候。一按點,編譯工具就會自動的把該對象可以使用的全部的方法和屬性所有都列出來,供用戶進行選擇。這就是利用了Java反射的原理,是對咱們建立對象的探知、自審。app

Constructor類

每一個Constructor對象都表明一個構造方法,利用Constructor對象能夠操做相應的構造方法。下面時Constructor類經常使用的方法以及它的做用;eclipse

  1. isVarArgs(),查看該構造方法是否容許帶有可變數量的參數,若是容許則返回true,不然返回false;方法原型:public boolean isVarArgs();
  2. getName(),以字符串的形式返回該構造方法的名字。方法原型:public String getName();
  3. getParameterTypes(),按照聲明順序以Class數組的形式得到該構造方法的各個參數類型。方法原型:public Class<?>[] getParameterTypes();
  4. getExceptionTypes(),以Class數組的形式得到該構造方法可能拋出的異常類型。方法原型:public Class<?>[] getExceptionTypes();
  5. newInstance(),經過該構造方法利用指定參數建立一個該類的對象,若是未設置參數則表示採用默認無參數的構造方法。函數原型:public T newInstance(Object... initargs),T表示返回的是一個Objec類的對象;

    注:Class.newInstance和Constructor.newInstance的有區別;Constructor的該方法可以使用有參數的構造方法,而Class下的該方法只可以使用無參默認構造方法。
  6. setAccessible(),若是該構造方法的權限爲private,默認不容許經過反射利用newInstance()方法建立對象;若是先執行該方法並將入口參數設爲true,則容許建立。方法原型:public void setAccessible(boolean flag);
    7.getModifiers(),得到能夠解析出該構造方法所採用的修飾符的整數(利用Modifier類下的toString方法能夠轉換成字符串)。方法原型:public int getModifiers()。

下面介紹幾個Modifier類經常使用的方法;

isPublic(int mod);

isProtected(int mod);

isPrivate(int mod);

isStatic(int mod);

isFinal(int mod);

toString(int mod);

這幾種方法的做用都顯而易見,再也不贅述。函數

下面看代碼示例:工具

//代碼示例 Main類
import java.lang.reflect.*;

public class Main_01 {

	public static void main(String[] args) {

		Example_01 example = new Example_01("10", "20", "30");
		Class<? extends Example_01> exampleC = example.getClass();

		Constructor[] declaredConstructors = exampleC.getDeclaredConstructors();
		for (int i = 0; i < declaredConstructors.length; i++) {
			Constructor<?> constructor = declaredConstructors[i];
			System.out.println("查看是否容許帶有可變數量的參數:" + constructor.isVarArgs());
			System.out.println("該構造方法的入口參數類型依次爲:");
			Class[] parameterTypes = constructor.getParameterTypes();
			for (int j = 0; j < parameterTypes.length; j++) {
				System.out.println(" " + parameterTypes[j]);
			}
			System.out.println("該構造方法可能拋出的異常類型爲:");
			Class[] exceptionTypes = constructor.getExceptionTypes();
			for (int j = 0; j < exceptionTypes.length; j++) {
				System.out.println(" " + exceptionTypes[j]);
			}
			Example_01 example2 = null;
			while (example2 == null) {
				try {
					if (i == 2)
						example2 = (Example_01) constructor.newInstance();
					else if (i == 1)
						example2 = (Example_01) constructor.newInstance("7", 5);
					else {
						Object[] parameters = new Object[] { new String[] {
								"100", "200", "300" } };
						example2 = (Example_01) constructor
								.newInstance(parameters);
					}
				} catch (Exception e) {
					System.out.println("在建立對象時拋出異常,下面執行setAccessible()方法");
					constructor.setAccessible(true);
				}
			}
			if(example2!=null){
			example2.print();
			System.out.println();
			
			}
		}

	}

}
//代碼示例 Example類
public class Example_01 {
	String s;
	int i, i2, i3;
	private Example_01() {
	}
	protected Example_01(String s, int i) {
		this.s = s;
		this.i = i;
	}
	public Example_01(String... strings) throws NumberFormatException {
		if (0 < strings.length)
			i = Integer.valueOf(strings[0]);
		if (1 < strings.length)
			i2 = Integer.valueOf(strings[1]);
		if (2 < strings.length)
			i3 = Integer.valueOf(strings[2]);
	}
	public void print() {
		System.out.println("s=" + s);
		System.out.println("i=" + i);
		System.out.println("i2=" + i2);
		System.out.println("i3=" + i3);
	}
}

這是運行結果截圖:

this

Filed類

每一個Field對象都表明一個成員變量,利用Field對象能夠操控相應的成員變量。下面是Field類的一些經常使用的方法以及做用;code

  1. getName(),得到該成員變量的名稱。方法原型:public String getName();
  2. getType(),得到表示該成員變量類型的Class對象。方法原型:public Class<?> getType();
  3. getModifiers(),得到能夠解析出該成員變量所採用修飾符的整數。方法原型:public int getModifiers();
  4. get(Object obj),得到指定對象obj中成員變量的值,返回類型爲Object型。方法原型:public Object get(Object obj);
  5. set(Object obj,Object value),將指定對象obj中成員變量的值設定爲value;
    還有具體到各類類型的get set方法,再也不一一介紹。另外說明:Object對象指的是已經實例化的反射對象。
    下面是代碼示例:
//代碼示例 Main類
import java.lang.reflect.*;
public class Main_02 {
	public static void main(String[] args) {
		Example_02 example = new Example_02();
		Class exampleC = example.getClass();
		// 得到全部成員變量
		Field[] declaredFields = exampleC.getDeclaredFields();
		for (int i = 0; i < declaredFields.length; i++) {
			Field field = declaredFields[i]; // 遍歷成員變量
			// 得到成員變量名稱
			System.out.println("名稱爲:" + field.getName());
			Class fieldType = field.getType(); // 得到成員變量類型
			System.out.println("類型爲:" + fieldType);
			boolean isTurn = true;
			while (isTurn) {
				// 若是該成員變量的訪問權限爲private,則拋出異常,即不容許訪問
				try {
					isTurn = false;
					// 得到成員變量值
					System.out.println("修改前的值爲:" + field.get(example));
					// 判斷成員變量的類型是否爲int型
					if (fieldType.equals(int.class)) {
						System.out.println("利用方法setInt()修改爲員變量的值");
						field.setInt(example, 168); // 爲int型成員變量賦值
						// 判斷成員變量的類型是否爲float型
					} else if (fieldType.equals(float.class)) {
						System.out.println("利用方法setFloat()修改爲員變量的值");
						// 爲float型成員變量賦值
						field.setFloat(example, 99.9F);
						// 判斷成員變量的類型是否爲boolean型
					} else if (fieldType.equals(boolean.class)) {
						System.out.println("利用方法setBoolean()修改爲員變量的值");
						// 爲boolean型成員變量賦值
						field.setBoolean(example, true);
					} else {
						System.out.println("利用方法set()修改爲員變量的值");
						// 能夠爲各類類型的成員變量賦值
						field.set(example, "MWQ");
					}
					// 得到成員變量值
					System.out.println("修改後的值爲:" + field.get(example));
				} catch (Exception e) {
					System.out.println("在設置成員變量值時拋出異常,"
							+ "下面執行setAccessible()方法!");
					field.setAccessible(true); // 設置爲容許訪問
					isTurn = true;
				}
			}
			System.out.println();
		}
	}
}
//代碼示例 Example類
public class Example_02 {
	int i;
	public float f;
	protected boolean b;
	private String s;
}

下面是運行結果:

orm

Method類

每一個Method對象表明一個方法,利用Method對象能夠操縱相應的方法。下面是Method類的一些經常使用的方法以及做用;

  1. getName(),得到該方法的名稱。方法原型:public String getName();
  2. getParameterTypes(),按照聲明的順序以Class數組的形式得到該方法的各個參數的類型。方法原型:public Class<?>[] getParameterTypes();
  3. getReturnType(),以Class對象的形式返回該方法的返回類型。方法原型:public Class<?> getReturnType();
  4. getExceptionTypes(),以Class數組的形式得到該方法可能拋出的異常。方法原型:public Class<?> getExceptionTypes();
  5. invoke(Object obj,Object···args),利用指定參數args執行指定對象obj中的該方法,返回值類型爲Object型。方法原型:public Object invoke(Object obj, Object... args);
  6. isVarArgs(),同Constructor;
  7. getModifiers(),同上。
    下面是代碼示例:
//代碼示例 Main類
import java.lang.reflect.*;

public class Main_03 {
	public static void main(String[] args) {
		Example_03 example = new Example_03();
		Class exampleC = example.getClass();
		// 得到全部方法
		Method[] declaredMethods = exampleC.getDeclaredMethods();
		for (int i = 0; i < declaredMethods.length; i++) {
			Method method = declaredMethods[i]; // 遍歷方法
			System.out.println("名稱爲:" + method.getName()); // 得到方法名稱
			System.out.println("是否容許帶有可變數量的參數:" + method.isVarArgs());
			System.out.println("入口參數類型依次爲:");
			// 得到全部參數類型
			Class[] parameterTypes = method.getParameterTypes();
			for (int j = 0; j < parameterTypes.length; j++) {
				System.out.println(" " + parameterTypes[j]);
			}
			// 得到方法返回值類型
			System.out.println("返回值類型爲:" + method.getReturnType());
			System.out.println("可能拋出的異常類型有:");
			// 得到方法可能拋出的全部異常類型
			Class[] exceptionTypes = method.getExceptionTypes();
			for (int j = 0; j < exceptionTypes.length; j++) {
				System.out.println(" " + exceptionTypes[j]);
			}
			boolean isTurn = true;
			while (isTurn) {
				// 若是該方法的訪問權限爲private,則拋出異常,即不容許訪問
				try {
					isTurn = false;
					if("staticMethod".equals(method.getName()))
						method.invoke(example); // 執行沒有入口參數的方法
					else if("publicMethod".equals(method.getName()))
						System.out.println("返回值爲:"
								+ method.invoke(example, 168)); // 執行方法
					else if("protectedMethod".equals(method.getName()))
						System.out.println("返回值爲:"
								+ method.invoke(example, "7", 5)); // 執行方法
					else if("privateMethod".equals(method.getName())) {
						Object[] parameters = new Object[] { new String[] {
								"M", "W", "Q" } }; // 定義二維數組
						System.out.println("返回值爲:"
								+ method.invoke(example, parameters));
					}
				} catch (Exception e) {
					System.out.println("在執行方法時拋出異常,"
							+ "下面執行setAccessible()方法!");
					method.setAccessible(true); // 設置爲容許訪問
					isTurn = true;
				}
			}
			System.out.println();
		}
	}
}
//代碼示例 Example
public class Example_03 {
	static void staticMethod() {
		System.out.println("執行staticMethod()方法");
	}
	
	public int publicMethod(int i) {
		System.out.println("執行publicMethod()方法");
		return i * 100;
	}
	
	protected int protectedMethod(String s, int i)
			throws NumberFormatException {
		System.out.println("執行protectedMethod()方法");
		return Integer.valueOf(s) + i;
	}
	
	private String privateMethod(String... strings) {
		System.out.println("執行privateMethod()方法");
		StringBuffer stringBuffer = new StringBuffer();
		for (int i = 0; i < strings.length; i++) {
			stringBuffer.append(strings[i]);
		}
		return stringBuffer.toString();
	}
}

下面是運行結果圖:

未完待更……2020-4-2

相關文章
相關標籤/搜索