工做奇談——JAVA高級特性之反射

1、從問題入手

      最近又要面試新人,因此翻了翻之前的代碼,忽然發現了一個有意思的問題。java

        問:以下一個Student類,請實例Student並對其成員變量賦值。面試

public class Student {
	
	private String NAME;
	
	private int AGE;

	@Override
	public String toString() {
		return "Student [name=" + NAME + ", age=" + AGE + "]";
	}

}

        若是是個入行沒多久或者基礎不太好的初學者來看,確定一臉蒙逼。兩個私有成員變量set,get方法也沒有,有參構造器也不提供,怎麼搞?ide

        其實也不難,首先看到這種只提供私有成員變量第一個想到的確定是反射。代碼以下:測試

public static void main(String[] args) throws Exception {
		Class clazz = Student.class;
		
		Object obj = clazz.newInstance();
		
		Field fieldName = clazz.getDeclaredField("name");
		Field fieldAge = clazz.getDeclaredField("age");
		
		fieldName.setAccessible(true);
		fieldAge.setAccessible(true);
		
		fieldName.set(obj, "二十歲之後");
		fieldAge.set(obj,21);
		
		System.out.println(obj);
	}

那麼什麼是反射呢?spa

    JAVA反射機制是在運行狀態中,對於任意一個類,都可以知道這個類的全部屬性和方法;對於任意一個對象,都可以調用它的任意方法和屬性;這種動態獲取信息以及動態調用對象方法的功能稱爲java語言的反射機制。 code

1.類的加載概述對象

當程序要使用某個類時,若是該類還未被加載到內存中,則系統會經過加載,鏈接,初始化三步來實現對這個類進行初始化。繼承

(1)加載 接口

就是指將class文件讀入內存,併爲之建立一個Class對象。內存

任何類被使用時系統都會創建一個Class對象。

(2)鏈接

1>驗證 : 是否有正確的內部結構,並和其餘類協調一致

2>準備 : 負責爲類的靜態成員分配內存,並設置默認初始化值

3>解析: 把類中的符號引用轉換爲直接引用

(3)初始化  就是類的初始化步驟 

2.類的加載時機

(1)建立類的實例

訪問類的靜態變量,或者爲靜態變量賦值

(2)調用類的靜態方法

使用反射方式來強制建立某個類或接口對應的java.lang.Class對象

(3)初始化某個類的子類

直接使用java.exe命令來運行某個主類

3.類加載器的概述

負責將.class文件加載到內在中,併爲之生成對應的Class對象。

4.類加載器的分類

Bootstrap ClassLoader 根類加載器

Extension ClassLoader 擴展類加載器

Sysetm ClassLoader     系統類加載器

5.類加載器的做用

(1)Bootstrap ClassLoader 根類加載器

也被稱爲引導類加載器,負責Java核心類的加載

好比System,String等。在JDK中JRE的lib目錄下rt.jar文件中

(2)Extension ClassLoader 擴展類加載器

負責JRE的擴展目錄中jar包的加載。

在JDK中JRE的lib目錄下ext目錄

(3)Sysetm ClassLoader 系統類加載器

負責在JVM啓動時加載來自java命令的class文件,以及classpath環境變量所指定的jar包和類路徑

/**

  * 反射: 就是發生在運行狀態下一種機制. 對於任意一個類咱們能夠獲取到該類的字節碼文件 對象 , 獲取到

  * 字節碼文件對象之後,咱們就能夠剖析找個類

  * java爲咱們的類中的每一種成員提供了對應的類對其進行描述:

  *

  * 成員變量 Field

  * 構造方法 Constructor

  * 成員方法 Method

  *

  * 獲取一個類對應的字節碼文件對象:

  *

  * (1): 經過調用getClass方法獲取該類對應的字節碼文件對象

  * (2): 經過靜態的class屬性獲取

  * (3): 咱們能夠經過Class類中的一個靜態方法叫作: forName(String className):

  * public static Class<?> forName(String className)

  *

  */

代碼示例以下:經過三種方式去得的到Person類對應的字節碼文件對象,如下輸出結果都爲True

/**  * 獲取構造方法的方法

//獲取全部公共的構造方法  * public Constructor<?>[] getConstructors()

// 獲取全部的構造方法,包括私有的  * public Constructor<?>[] getDeclaredConstructors()

//獲取帶指定參數的共有構造方法  * public Constructor<T> getConstructor(Class... parameterTypes)  * public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)  */

代碼示例爲獲取Student類的全部構造方法:

Student類:

測試代碼,獲取Student類的三個構造方法

輸出爲

測試代碼,獲取Student類參數爲兩個的公有構造器,並實例化對象

結果爲:

經過反射得到類中的成員變量並使用

一共四個方法能夠獲取

getField(String name):獲取單個成員變量,指定的成員變量對應的名稱

getFields():獲取的是全部公共的成員變量,包含從父類中繼承過來的

getDeclaredFields():獲取的是本類中全部的成員變量,包含私有的

getDeclaredField(String name):獲取本類中指定成員變量

其中Student成員變量都爲private提供Set、Get方法,且不經過兩個參數的構造器實例化對象

相關文章
相關標籤/搜索