對於類型與反射,我的理解是在運行時可以動態地對類進行一些操作。
比如:XXX x = new XXX()
這個 XXX
我是可以外部輸入的,輸入"Cat" 的時候就是 Cat x = new Cat()
,輸入"Dog" 的時候,就是 Dog x = new Dog()
。
但是這在一般的編程是很難這樣動態地做到的,因此需要反射。
運行 Java 文件的過程
Java 文件的運行過程是這樣的:
xxx.java -> 編譯 -> xxx.class -> 運行
通俗來講,每個類型要變成一份“說明書”(xxx.class),然後在 new XXX()
的時候是根據這份“說明書”來創建對象的。
這不禁讓我們想到:能不能在運行的時候去修改這份說明書,比如加入變量,修改裏面方法等,然後再根據這份“修改過的說明書”去 new 對象呢?
ClassLoader
爲了去更深入想上面的問題,先來看看這個玩意:ClassLoader,它負責從外部加載一個類,也就是我們的 xxx.java -> 編譯 -> xxx.class
這一步。這個很容易理解,就相當於編譯器嘛。
不過它也有下面特點:
- 對應的 Java 文件不一定存在,可以是 Stream,自己創建 Class
- 對應的字節碼不一定存在,動態創建 Class
上面的這些特點不禁讓我們想到可以“動態地”修改“說明書”了。
反射
反射就是可以在運行的時候去修改這份說明書的,然後我們可以調用 ClassLoader 去編譯其實就是我們所說的動態XXXX。有了反射,我們可以
- 動態創建一個對象
- 動態調用一個方法
- 動態獲取一個屬性
動態創建一個對象
String className = args[0];
Class c = Class.forName(className);
Object obj = c.getConstructor().newInstance();
動態調用一個方法
Cat cat = new Cat();
cat.getClass().getMethod(args[0]).invoke();
動態獲取一個屬性
Cat cat = new Cat();
cat.getClass().getField(args[0]).get(cat)
雙親委派模型
看名字就看不懂,意思其實很簡單,如果一個類如 String 已經聲明,然後你再別的地方再聲明 String,那你的 String 並不會被加載。僞代碼如下:
if (java.lang 包裏有沒有 String 類被加載?) {
不管了,直接結束
} else {
load(自己寫的包的 String 類)
}