本文目錄一覽:
java中反射實例類裝載的步驟及簡要闡述
java反射和類裝載
反射機制:
Person p=new Person();
這是什麼?當然是實例化一個對象了.可是這種實例化對象的方法存在一個問題,那就是必須要知道類名才可以實例化它的對象,這樣我們在應用方面就會受到限制.那麼有沒有這樣一種方式,讓我們不知道這個類的類名就可以實例化它的對象呢?Thank Goodness!幸虧我們用的是java, java就提供了這樣的機制.
1).java程序在運行時可以獲得任何一個類的位元組碼信息,包括類的修飾符(public,static等),基類(超類,父類),實現的介面,欄位和方法等信息.
2).java程序在運行時可以根據位元組碼信息來創建該類的實例對象,改變對象的欄位內容和調用對象方法.
這樣的機制就叫反射技術.可以想像光學中的反射,就像我們照鏡子,鏡子中又出現一個自己(比喻可能不太恰當,但是足以表達清楚意思了).反射技術提供了一種通用的動態連接程序組件的方法,不必要把程序所需要的目標類硬編碼到源程序中,從而使得我們可以創建靈活的程序.
反射的實現步驟( 不問不需要答) ,
1、獲取類的常用方式有三種: a) Class.forName(“包名.類名”),最常用、推薦;b) 包名.類名.class 最簡捷;c) 對象.getClass 的方式獲得。
2、對象的實例化,上面已經獲取了類,只需要調用類的實例化方法,類.newInstance()便可。
3、獲取屬性和構造等,可以參考 JavaApi 的調用,類. getDeclaredFields,類. getConstructor(..)等。
Java的反射機制是通過反射API來實現的,它允許程序在運行過程中取得任何一個已知名稱的類的內部信息.反射API位於java.lang.reflect包中.主要包括以下幾類:
1).Constructor類:用來描述一個類的構造方法
2).Field類:用來描述一個類的成員變數
3).Method類:用來描述一個類的方法.
4).Modifer類:用來描述類內各元素的修飾符
5).Array:用來對數組進行操作.
Constructor,Field,Method這三個類都是JVM(虛擬機)在程序運行時創建的,用來表示載入類中相應的成員.這三個類都實現了java.lang.reflect.Member介面,Member介面定義了獲取類成員或構造方法等信息的方法.要使用這些反射API,必須先得到要操作的對象或類的Class類的實例.通過調用Class類的newInstance方法(只能調用類的默認構造方法)可以創建類的實例.這樣有局限性,我們可以先沖類的Class實例獲取類需要的構造方法,然後在利用反射來創建類的一個實例.
類載入機制:

類的載入機制可以分為載入-鏈接-初始化三個階段,鏈接又可以分為驗證、準備、解析三個過程。
載入:通過類的載入器查找並載入二進位位元組流的過程,在堆內存中的方法區生成 一個代表這個類的 java.lang.Class 對象,作為這個類的數據請求入口。(這裡可以把上面類載入器載入文件的過程描述一下(參考版本一,不作重複))。
驗證:主要是對一些詞法、語法進行規範性校驗,避免對 JVM 本身安全造成危害; 比如對文件格式,位元組碼驗證,無數據驗證等。但驗證階段是非必須的,可以通過參數 設置來進行關閉,以提高載入的時效。
準備:對類變數分配內存,並且對類變數預初始化,初始化成數據類型的原始值, 比如 static int a=11,會被初始化成成 a=0;如果是 static double a =11,則會被初始化成 a=0.0; 而成員變數只會成實例化後的堆中初始化。
解析:把常量池中的符號引用轉換為直接引用的過程。
初始化:對類的靜態變數和靜態塊中的變數進行初始化。(上面的準備階段可以作為 預初始化,初始到變數類型的原值,但如果被 final 修飾會進行真正初始化)
上面載入、鏈接、初始化的各個階段並不是彼此獨立,而是交叉進行,這點很重要 。
***class.forName和 classloader的區別
Class.forName 和 ClassLoader 都是用來裝載類的,對於類的裝載一般為分三個階段載入、鏈接、編譯,它們裝載類的方式是有區別。
首先看一下 Class.forName(..),forName(..)方法有一個重載方法 forName(className,boolean,ClassLoader),它有三個參數,第一個參數是類的包路徑,第二個參數是 boolean
類型,為 true 地表示 Loading 時會進行初始化,第三個就是指定一個載入器;當你調用class.forName(..)時,默認調用的是有三個參數的重載方法,第二個參數默認傳入 true,第三個參數默認使用的是當前類載入時用的載入器。
ClassLoader.loadClass()也有一個重載方法,從源碼中可以看出它默認調的是它的重載 方法 loadClass(name, false),當第二參數為 false 時,說明類載入時不會被鏈接。這也是兩者之間最大區別,前者在載入的時候已經初始化,後者在載入的時候還沒有鏈接。如果你需要在載入時初始化一些東西,就要用 Class.forName 了,比如我們常用的驅動載入, 實際上它的註冊動作就是在載入時的一個靜態塊中完成的。所以它不能被 ClassLoader 載入代替。
北大青鳥設計培訓:Java類載入機制?
1,類的載入每個開發人員對java.lang.ClassNotFoundExcetpion這個異常肯定都不陌生,這背後就涉及到了java技術體系中的類載入。
Java的類載入機制是技術體系中比較核心的部分,雖然和大部分開發人員直接打交道不多,但是對其背後的機理有一定理解有助於排查程序中出現的類載入失敗等技術問題,對理解java虛擬機的連接模型和java語言的動態性都有很大幫助。
那麼什麼是類的載入?類的載入指的是將類的.class文件中的二進位數據讀入到內存中,將其放在運行時數據區的方法區內,然後在堆區創建一個java.lang.Class對象,用來封裝類在方法區內的數據結構。
類的載入的最終產品是位於堆區中的Class對象,Class對象封裝了類在方法區內的數據結構,並且向Java程序員提供了訪問方法區內的數據結構的介面。
類載入器是Java語言的一個創新,也是Java語言流行的重要原因之一。
它使得Java類可以被動態載入到Java虛擬機中並執行。
類載入器從JDK1.0就出現了,最初是為了滿足JavaApplet的需要而開發出來的。
JavaApplet需要從遠程下載Java類文件到瀏覽器中並執行。
現在類載入器在Web容器和OSGi中得到了廣泛的使用,而類載入器並不需要等到某個類被「首次主動使用」時再載入它,JVM規範允許類載入器在預料某個類將要被使用時就預先載入它,如果在預先載入的過程中遇到了.class文件缺失或存在錯誤,類載入器必須在程序首次主動使用該類時才報告錯誤(LinkageError錯誤)如果這個類一直沒有被程序主動使用,那麼類載入器就不會報告錯誤。
2,類的生命周期類載入的過程中包括有載入,驗證,準備,解析,初始化五個階段。
而需要注意的是在這五個階段中,載入、驗證、準備和初始化這四個階段發生的順序是確定的,而解析階段則不一定,它在某些情況下可以在初始化階段之後開始,這是為了支持Java語言的運行時綁定(也成為動態綁定或晚期綁定)。
另外注意這裡的幾個階段是按順序開始,而不是按順序進行或完成,因為這些階段通常都是互相交叉地混合進行的,通常在一個階段執行的過程中調用或激活另一個階段。
載入:查找並載入類的二進位數據載入時類載入過程的第一個階段,在載入階段,虛擬機需要完成以下三件事情:1、通過一個類的全限定名來獲取其定義的二進位位元組流。
(並沒有指明要從一個Class文件中獲取,可以從其他渠道,譬如:網路、動態生成、資料庫等)2、將這個位元組流所代表的靜態存儲結構轉化為方法區的運行時數據結構。
3、在Java堆中生成一個代表這個類的java.lang.Class對象,作為對方法區中這些數據的訪問入口。
相對於類載入的其他階段而言,載入階段(準確地說,是載入階段獲取類的二進位位元組流的動作)是可控性最強的階段,電腦培訓發現因為開發人員既可以使用系統提供的類載入器來完成載入,也可以自定義自己的類載入器來完成載入。
描述一下JVM載入class文件的原理?
Java語言是一種具有動態性的解釋型語言,類(class)只有被載入到JVM中後才能運行。當運行指定程序時,JVM會將編譯生成的.class文件按照需求和一定的規則載入到內存中,並組織成為一個完整的Java應用程序。這個載入過程是由類載入器來完成的,具體來說,就是由ClassLoader和它的子類來實現的。類載入器本身也是一個類,其實質是把類文件從硬碟讀取到內存中。
類的載入方式分為隱式載入與顯式載入兩種。隱式載入指的是程序在使用new等方法創建對象時,會隱式地調用類的載入器把對應的類載入到JVM中。顯式載入指的是通過直接調用class.forName()方法來把所需要的類載入到JVM中。
任何一個工程項目都是由許多個類組成的,當程序啟動時,只把需要載入的類載入到JVM中,其他類只有被使用到的時候才會被載入,採用這種方法,一方面可以加快載入速度,另外一方面可以節約程序運行過程中對內存的開銷。此外,在Java語言中,每個類或介面都對應一個.class文件,這些文件可以被看成一個個可以被動態載入的單元,因此當只有部分類被修改時,只需要重新編譯變化的類即可,而不需要重新編譯所有文件,因此加快了編譯速度。
jvm載入類的過程的問題?
類從載入到虛擬機到卸載,它的整個生命周期包括:載入(Loading),驗證(Validation),準備(Preparation),解析(Resolution),初始化(Initialization),使用(Using)和卸載(Unloading)。其中,驗證、準備和解析部分被稱為連接(Linking)。
載入:
在載入階段,虛擬機主要完成三件事:
1.通過一個類的全限定名來獲取定義此類的二進位位元組流。
2.將這個位元組流所代表的靜態存儲結構轉化為方法區域的運行時數據結構。
3.在Java堆中生成一個代表這個類的java.lang.Class對象,作為方法區域數據的訪問入口。
驗證:
驗證階段作用是保證Class文件的位元組流包含的信息符合JVM規範,不會給JVM造成危害。如果驗證失敗,就會拋出一個java.lang.VerifyError異常或其子類異常。驗證過程分為四個階段:
1.文件格式驗證:驗證位元組流文件是否符合Class文件格式的規範,並且能被當前虛擬機正確的處理。
2.元數據驗證:是對位元組碼描述的信息進行語義分析,以保證其描述的信息符合Java語言的規範。
3.位元組碼驗證:主要是進行數據流和控制流的分析,保證被校驗類的方法在運行時不會危害虛擬機。
4.符號引用驗證:符號引用驗證發生在虛擬機將符號引用轉化為直接引用的時候,這個轉化動作將在解析階段中發生。
準備:
準備階段為變數分配內存並設置類變數的初始化。在這個階段分配的僅為類的變數(static修飾的變數),而不包括類的實例變數。對已非final的變數,JVM會將其設置成「零值」,而不是其賦值語句的值:
pirvate static int size = 12;
那麼在這個階段,size的值為0,而不是12。 final修飾的類變數將會賦值成真實的值。
解析:
解析過程是將常量池內的符號引用替換成直接引用。主要包括四種類型引用的解析。類或介面的解析、欄位解析、方法解析、介面方法解析。
初始化:
在準備階段,類變數已經經過一次初始化了,在這個階段,則是根據程序員通過程序制定的計划去初始化類的變數和其他資源。這些資源有static{}塊,構造函數,父類的初始化等。
至於使用和卸載階段階段,這裡不再過多說明,使用過程就是根據程序定義的行為執行,卸載由GC完成。
參考資料:
《深入Java虛擬機》 周志明
《深入JAVA虛擬機第二版》 Bill Venners
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/247941.html