java中成员变量的加载时机_工作奇谈——JAVA高级特性之反射
一、從問題入手
最近又要面試新人,所以翻了翻以前的代碼,突然發現了一個有意思的問題。
問:如下一個Student類,請實例Student并對其成員變量賦值。
public class Student {
private String NAME;
private int AGE;
@Override
public String toString() {
return "Student [name=" + NAME + ", age=" + AGE + "]";
}
}
如果是個入行沒多久或者基礎不太好的初學者來看,肯定一臉蒙逼。兩個私有成員變量set,get方法也沒有,有參構造器也不提供,怎么搞?
其實也不難,首先看到這種只提供私有成員變量第一個想到的肯定是反射。代碼如下:
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);
}
那么什么是反射呢?
JAVA反射機制是在運行狀態中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調用它的任意方法和屬性;這種動態獲取信息以及動態調用對象方法的功能稱為java語言的反射機制。
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?getConstructor(Class...?parameterTypes) ?*?public?Constructor?getDeclaredConstructor(Class>...?parameterTypes) ?*/
代碼示例為獲取Student類的所有構造方法:
Student類:
測試代碼,獲取Student類的三個構造方法
輸出為
測試代碼,獲取Student類參數為兩個的公有構造器,并實例化對象
結果為:
通過反射獲得類中的成員變量并使用
一共四個方法可以獲取
getField(String?name):獲取單個成員變量,指定的成員變量對應的名稱
getFields():獲取的是所有公共的成員變量,包含從父類中繼承過來的
getDeclaredFields():獲取的是本類中所有的成員變量,包含私有的
getDeclaredField(String?name):獲取本類中指定成員變量
其中Student成員變量都為private且不提供Set、Get方法,且不通過兩個參數的構造器實例化對象
總結
以上是生活随笔為你收集整理的java中成员变量的加载时机_工作奇谈——JAVA高级特性之反射的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SpringBoot 轻松搞定数据验证
- 下一篇: 缓存加速CDN——squid代理服务器应