在談論到反射這個問題時,你是否有如下疑問?
無論是在.NET還是Java中反射的原理和機制是一樣的,理解了一種另一種就可以迎刃而解,想要理解反射首先需要了解底層的一些概念和運行,理解了反射有助于你理解程序的運行原理,目前很多框架(java、.NET)中都引入了反射這一個技術,反射其實也不是什么新的技術只是幾個不同的操作過程集成到一起關聯起來了。
從表面上我們看到的效果是這樣的:通過傳入一個字符串可以得到某個類的對象,在這一個過程中做了很多事情。你是否有下面的一些疑問存在?
JDK、JRE是一回事嗎?
JRE和JVM有聯系嗎?
JVM和類加載器什么關系?
類加載器加載類的過程?
反射和類加載之間有什么神秘關系?
看完這篇文章,也許你會對反射有一個清晰的認識。
JDK是為我們開發提供的一個開發類庫,里面存在著大量的開發類,而JRE是開發好的程序運行的環境,也就是說你的電腦上如果想運行java程序可以沒有JDK,但要有JRE這個運行環境,往往下載了JDK開發包已經包含了JRE這個環境,安裝時是可以選擇不安裝JRE的,你開發好的程序都需要測試、運行等,因此有必要安裝JRE。
而JVM是存在JRE這個環境里的,只是在JRE這個環境里面不止僅有JVM,JVM是必須的,如果沒有其它的類輔助JVM運行,JVM是沒有辦法運行的,舉個簡單的例子來看看好想紅花也許綠葉來襯托、如果沒有綠葉的襯托怎么會顯示出紅花的價值呢。
類加載器這些類是JVM提供的,負責把類(.class文件)讀入到內存中,并且為每個加載到內存中的類創建一個Class對象,你可以理解為一般我們看到的類都有一個超類Class,當一個類加載時就會為這個類實例化一個Class對象,這個對象負責唯一標示該類,事實表明這個Class對象非常有用,如論是反射還是注解等的實現都依賴于這一對象,我們通過這個Class對象里面的方法可以獲取到任何一個類的所有方法(包括父類集成來的)、所有字段(包括私有屬性)、構造器等等,在上一篇注解博客中核心就是利用了Class對象的getMethods()方法,得到一個類的所有方法,然后循環判斷注解才實現對注解方法起作用。
獲得Class對象的三種方式
1.Class類的forName(String clazzName)
2.調用某個類的class屬性,如Person.class
3.某個對象的getClass()方法
類加載的步驟(想了解的更細節可以看一下JVM規范)
1.加載
指的是將.class文件讀入內容,并為之創建一個Class對象;可以理解為所有的類也是實例,它們都是java.lang.Class這個類的實例。
加載類的途徑
A:從本地文件系統中加載.class文件
B:從JAR包中加載.class文件,例如你連接mysql或oracle數據庫時,是不是有一個驅動jar包,驅動類都放在這個jar中,再多說一點:關于驅動jar文件,一個驅動可以連接哪個數據庫或者支持啥功能,本地事務還是全局事務,主要看驅動里面支持不支持。
C:網絡加載
D;java文件先編譯,再加載
2.連接
將內容中的.class二進制文件讀入到JRE代表的進程內容中,又分為驗證、準備、解析三個過程。
3.初始化
主要是對一些靜態字段賦值操作,初始化時可能并沒有類的實例呢,所以是只初始化類范圍的變量,如static修飾的變量。
初始化不僅僅是對目標類初始化,如果它有繼承的父類,它的父類會都初始化,我們知道所有類都是object的子類,object每次都會被初始化,這也解析了為什么你可以調用Object這個類的方法,因此它也初始化了。
類加載器
從上圖中我們可以得知哪些類加載器以及它們主要負責加載哪些類,其中MyClassLoader1/2是自定義類加載器,可以從指定目錄加載類,即.java文件不再classpath路徑下也可以加載,有時我們會遇到找不到類的問題,其實就是類路徑寫的不錯。
類加載器加載類算法?
內存管理、CUP調度等都有自己的算法,比如先進先出、最早使用原則,寫算法的目的是實現資源合理調配,從各種方案中找到一種可以解決實際問題的思路,類再加載類時也存在這樣的問題,如遇到一個.class類后,讓哪一個加載器加載?去哪里找加載的類?等等,電腦是很傻的,不要把電腦想的很聰明,不要讓電腦去做選擇,它的選擇是我們給它指定的。
算法
依賴原則:當一個類加載時,它所依賴的類同時被加載。
尊老愛幼::針對加載器,每次加載類都讓著長輩,父加載器優先。
緩存:所有加載好的類放入一個緩存中,加載某個類時先去緩存中查找,不存在的話才去加載(如果你修改了一個加載好的類,也是存在的不去重新加載),這也是為什么每次我們修改了一個類后,需要重新啟動tomcat即重啟JVM。
上面這些是實現反射的基礎,總結就兩點一是Class對象;而是類加載器;反射主要是依賴于java的這兩個特性實現的反射過程,下篇中將用一個實例來實現反射,通過從屬性文件或者配置文件中讀取類的字符串信息來實例化類,Spring框架也是利用的這一個過程實現依賴注入的。
對于底層的一些東西覺的還是有必要理解、并可以使用,各種框架都依賴于底層,這對學習框架也是很有幫助的。