類加載器、反射和子產品化
一.類加載器
1. 類加載
當程式要使用某個類時,如果該類還未被加載到記憶體中,則系統會通過類的加載,類的連接配接,類的初始化這三個步驟來對類進行初始化。如果不出現意外情況, JVM将會連續完成這三個步驟,是以有時也把這三個步驟統稱為類加載或者類初始化
類的加載:
●就是指将class檔案讀入記憶體, 并為之建立一個java.lang.Class對象
●任何類被使用時,系統都會為之建立一個java.lang.Class 對象
類的連接配接:
●驗證階段: 用于檢驗被加載的類是否有正确的内部結構,并和其他類協調一緻
●準備階段: 負責為類的類變量配置設定記憶體,并設定預設初始化值
●解析階段: 将類的二進制資料中的符号引用替換為直接引用
類的初始化:
●在該階段,主要就是對類變量進行初始化
類的初始化步驟:
●假如類還未被加載和連接配接, 則程式先加載并連接配接該類
●假如該類的直接父類還未被初始化, 則先初始化其直接父類
●假如類中有初始化語句, 則系統依次執行這些初始化語句
注意:在執行第2個步驟的時候,系統對直接父類的初始化步驟也遵循初始化步驟1-3
類的初始化時機:
●建立類的執行個體
●調用類的類方法
●通路類或者接口的類變量, 或者為該類變量指派
●使用反射方式來強制建立某個類或接口對應的java.lang.Class對象
●初始化某個類的子類
●直接使用java.exe指令來運作某個主類
2.類加載器
類加載器的作用:
●負責将.class檔案加載到記憶體中,并為之生成對應的java.lang.Class對象。
●雖然我們不用過分關心類加載機制, 但是了解這個機制我們就能更好的了解程式的運作
JVM的類加載機制:
●全額負責: 就是當一個加載器負責載某個Class時,該Class所依賴的和引用的其他Class也将由該類加載器負責載入,除非顯示使用另外一個類載器來載入。
●父類委托:就是當一個類加載器負責加載某個Class時, 先讓父類加載器試圖加載該Class,隻有在父類加載器無法加載該類時才嘗試從自己的類路徑中加載該類。
●緩存機制: 保證所有加載過的Class都會被緩存,當程式需要使用某個Class對象時,類載器先從緩存區中搜尋該Class,隻有當緩存區中不存在該Class對象時,系統才會讀取該類對應的二進制資料,并将其轉換成Class對象,存儲到緩存區。
ClassLoader:是負責加載類的對象
Java運作時具有以下内置類加載器:
●Bootstrap class loader:它是虛拟機的内置類加載器通常表示為null,并且沒有父null。
●Platform class loader:平台類加載器可以看到所有平台類,平台類包括由平台類加載器或其祖先定義的Java SE平台API,實作類和JDK特定的運作時類。
●System class loader:它也被稱為應用程式類加載器,與平台類加載器不同。系統類加載器通常用于定義 應用程式類路徑,子產品路徑和JDK特定工具上的類。
●類加載器的繼承關系:System的父加載器為Platform, 而Platform的父加載器為Bootstrap。
ClassLoader中的兩個方法:
●static ClassLoader getSystemClassLoader():傳回用于委派的系統類加載器
●Classloader getParent():傳回父類加載器進行委派
二.反射
1.反射概述
Java反射機制:是指在運作時去擷取一個類的變量和方法資訊。然後通過擷取到的資訊來建立對象,調用方法的一種機制。由于這種動态性,可以極大的增強程式的靈活性,程式不用在編譯期就完成确定,在運作期仍然可以擴充。
2.擷取Class類的對象
我們要想通過反射去使用一個類,首先我們要擷取到該類的位元組碼檔案對象,也就是類型為Class類型的對象
這裡我們提供三種方式擷取Class類型的對象:
●使用類的class屬性來擷取該類對應的Class對象。舉例: Student.class将會傳回Student類對應的Class對象
●調用對象的getClass()方法,傳回該對象所屬類對應的Class對象。
該方法是Object類中的方法,所有的Java對象都可以調用該方法。
●使用Class類中的靜态方法forName(String className),方法需要傳入字元串參數,該字元串參數的值是某
個類的全路徑,也就是完整包名的路徑。
3.反射擷取構造方法并使用
Class類中用于擷取構造方法的方法
●Constructor<?> [] getConstructors(): 傳回所有公共構造方法對象的數組
●Constructor<?> [] getDeclaredConstructors(): 傳回所有構造方法對象的數組
●Constructor<T> getConstructor(Class <?> … parameterTypes):傳回單個公共構造方法對象
●Constructor<T> getDeclaredConstructor(Class<?> …parameterTypes):傳回單個構造方法對象
Constructor類中用于建立對象的方法:
●T newlnstance(Object….initargs):根據指定的構造方法建立對象
基本資料類型可以通過.class得到對應的Class類型。
public void setAccessible(boolean flag):值為true,取消通路檢查。
4.反射擷取成員變量并使用
Class類中于擷取成員量的方法
●Field [] getFields():傳回所有公共成員變量對象的數組
●Field [] getDeclaredFields():傳回所有成員變量對象的數組
●Field getField(String name):傳回單個公共成員變量對象
●Field getDeclaredField(String name):傳回單個成員變量對象
Field類中用于給成員量指派的方法:
void set(Object obj, Object value):給obj對象的成員變量指派為value
5.反射擷取成員方法并使用
Class類中用于擷取成員方法的方法
●Method [] getMethods(): 傳回所有公共成員方法對象的數組,包括繼承的
●Method [] getDeclaredMethods(): 傳回所有成員方法對象的數組,不包括繼承的
●Method getMethod(String name, Class <?> .. parameterTypes): 傳回單個公共成員方法對象
●Method getDeclaredMethod(String name, Class <?> .. parameterTypes): 傳回單個成員方法對象
Method類中用于調用成員方法的方法:
●Object invoke(Object obj, Object... args): 調用obj對象的成員方法,參數是args,傳回值是Object型
三.子產品化
1.子產品的基本使用
子產品的基本使用步驟
●建立子產品(按照以前的講解方式建立子產品,建立包,建立類,定義方法)
為了展現子產品的使用,我們建立2個子產品。一個是myOne, 一個是myTwo。
●在子產品的src目錄下建立一個名為module- info.java的描述性檔案,該檔案專門定義子產品名,通路權限,子產品依賴等資訊。
描述性檔案中使用子產品導出和子產品依賴來進行配置并使用。
●子產品中所有未導出的包都是子產品私有的, 他們是不能在子產品之外被通路的
在myOne這個子產品下的描述性檔案中配置子產品導出
子產品導出格式: exports 包名;
●一個子產品要通路其他的子產品,必須明确指定依賴哪些子產品,未明确指定依賴的子產品不能通路
在myTwo這個子產品下的描述性檔案中配置子產品依賴
子產品依賴格式: requires 子產品名;
注意:寫子產品名報錯,需要按下Alt+ Enter提示,然後選擇子產品依賴
●在myTwo這個子產品的類中使用依賴子產品下的内容
2.子產品服務的使用
子產品服務的使用步驟
●在myOne子產品下建立一個包com.itheima_03,在該包下提供一個接口, 接口中定義一個抽象方法
public interface MyService {
void service();
●在com.itheima_03包下建立一個包impl, 在該包下提供接口的兩個實作類Itheima和Czxy
●在myOne這個子產品下的描述性檔案中添加如下配置:
子產品導出: exports com.itheima_03;
服務提供: provides MyService with Itheima;
指定MyService的服務實作類是Itheima
●在myTwo這個子產品下的描述性檔案中添加如下配置:
聲明服務接口: uses MyService;
●在myTwo這個子產品的類中使用MyService接口提供的服務
ServiceLoader: 一種加載服務實作的工具