Java讀書筆記(6)-類的加載機制與反射

ch18 類加載機制與反射java

  1. 類的加載,鏈接和初始化數據庫

    系統可能在第一次使用某個類時加載該類,也可能採用預加載機制來加載某個類數組

    • JVM和類緩存

      • 一個Java程序就是一個Java虛擬機進程網絡

      • 兩個JVM之間數據獨立,因此一個類的靜態屬性並不會跨虛擬機進程共享框架

    • 類的加載spa

      • 加載->鏈接->初始化代理

      • 類加載是指將類的class文件讀入內存,併爲之建立一個java.lang.Class對象,當程序中使用任何類時,系統都將爲之創建一個java.lang.Class對象orm

      • 系統中的全部類實際上也是實例,它們都是java.lang.Class的實例對象

      • 類的加載由類加載器完成,類加載器一般由JVM提供,JVM提供的這些類加載器一般被稱爲系統類加載器。除此以外,開發者能夠經過繼承ClassLoader基類來建立本身的類加載器

      • 類的來源:

        1. 本地文件系統class

        2. JAR

        3. 網絡

        4. 動態編譯Java文件

    • 類的鏈接

      • 驗證->準備->解析

    • 類的初始化

      • 在類的初始化階段,虛擬機負責對類進行初始化,主要就是對靜態Field進行初始化

      • Java初始化靜態Field:聲明時指定初始值或使用靜態初始化塊

      • JVM初始化一個類的步驟:

        1. 如未加載和鏈接,則加載並鏈接該類

        2. 如其直接父類未初始化,則先初始化其直接父類

        3. 若有初始化語句,則依次執行這些初始化語句

      當執行步驟2時,系統對直接父類的初始化步驟也遵循此步驟13,依次迭代直到java.lang.Object類。當程序主動

      使用任何一個類時,系統會保證該類以及全部父類(包括直接父類和間接父類)都被初始化

    • 類初始化的時機

      • Java程序首次經過下面6種方式使用某個類或者接口時,系統就會初始化該類或接口:

        1. 建立類的實例 (new,反射,反序列化)

        2. 調用某個類的靜態方法

        3. 訪問(讀寫)某個類或接口的靜態Field

        4. 使用反射方式強制建立某個類或接口對應的java.lang.Class對象,如Class.forName(「Person」)

        5. 初始化某個類的子類

        6. 直接使用java.exe運行某個主類

      • final型靜態Field在編譯時就能定下來,故不會觸發類初始化行爲

      • 當使用ClassLoader類的loadClass()方法來加載某個類時,該方法只是加載該類,並不會執行該類的初始化。

      • 使用ClassforName()靜態方法纔會致使強制初始化該類

  1. 類加載器

    負責將.class文件加載到內存中,併爲之生成對應的java.lang.Class對象

    • 類加載器簡介

      • JVM中,一個類用其全限定類名和其類加載器做爲其惟一標識

      • JVM啓動時,會造成由3個類加載器組成的初始類加載器層次結構

        1. Bootstrap ClassLoader:根類加載器(引導類加載器,負責加載Java的核心類)

        2. Extension ClassLoader:擴展類加載器

        3. System ClassLoader:系統類加載器(JVM啓動時加載來自java命令的-classpath選項,java.class.path

        4. 系統屬性或者CLASSPATH環境變量所指定的JAR包和類路徑。程序均可以經過ClassLoader的靜態方法getSystemClassLoader()獲取系統類加載器)

    • 類加載機制

      • 類型:全盤負責,父類委託,緩存機制

      • 層級關係:用戶類加載器->系統類加載器->擴展類加載器->根類加載器

      • getParent()方法

      • 根類加載器不是由Java實現的

      • 系統類加載器是AppClassLoader的實例,擴展類加載器是ExtClassLoader的實例,這兩個類都是URLClassLoader的實例

      • 類加載class8個步驟

    • 建立並使用自定義的類加載器

      • JVM中除了根類加載器以外的全部類加載器都是ClassLoader子類的實例

      • 經過擴展ClassLoader子類,重寫包含的方法能夠實現自定義類加載器

      • 兩個關鍵方法:

        1. loadClass(String name,boolean resolve)

        2. findClass(String name)

      • 推薦重寫findClass()方法,而不是loadClass()方法

      • loadClass()執行步驟:

        1. findLoadedClass(String)來檢查是否已經加載類,若是已經加載則返回;

        2. 在父類加載器上調用loadClass()方法。若是父類加載器爲null,則使用根類加載器來加載;

        3. 調用findClass(String)方法查找類。

      • 核心方法Class defineClass(String name,byte[] b,int off,int len),該方法負責將指定類的字節碼文件(class文件)讀入字節數組byte[] b內,並把它轉換爲Class對象

    • URLClassLoader

      • 兩個構造器建立ClassLoader對象

      • 經過loadClass()方法能夠加載指定類

      • 應用:從文件系統加載MySQL驅動,並使用該驅動來獲取數據庫鏈接、

  2. 經過反射查看類信息

    • 獲取Class對象

      • 三種方式:

        1. Class.forName(String),傳入包含完整包名的全限定類名稱

        2. 調用某個類的class屬性來獲取該類對應的Class對象

        3. 調用某個對象的getClass()方法

    • Class中獲取信息

      • 構造器

      • Field

      • 方法

      • Annotation

  3. 使用反射生成並操做對象

    • 建立對象

      • 使用Class對象的newInstance()方法來建立該Class對象對應類的實例,要求該Class對象的對應類有默認構造器

      • 使用Class對象獲取指定的Constructor對象,再調用Constuctor對象的newInstance()方法來建立該Class對象對應的實例。經過這種方式能夠選擇使用指定的構造器來建立實例

      • 在不少JavaEE框架中都須要根據配置文件信息來建立Java對象,從配置文件讀取的只是某個類的字符串類名,程序須要根據該字符串來建立對應的實例,就必須使用反射

    • 調用方法

      • geMethods()方法或者getMethod()方法獲取所有方法或者指定方法——分別返回Method對象數組或者Method對象

      • 得到Method對象後,就可經過該Methodinvoke(Object obj,Object...args)調用相應的方法,obj是執行該方法的主調,後面的args是執行該方法時傳入該方法的實參

      • 權限問題:setAccessible(boolean flag),實現經過反射來調用private方法,private構造器和訪問private屬性

    • 訪問屬性值

      • 經過Class對象的getFields()getField()方法能夠獲取該類所包括的所有Field或指定Field

    • 操做數組

      • java.lang.reflect包下還提供了一個Array類,Array對象能夠表明全部的數組。程序能夠經過Array來動態建立數組,操做數組元素等

      • Object arr=Array.newInstance(String.class,10)

  4. 使用反射生成JDK動態代理

    • 使用ProxyInvocationHandler建立動態代理

      • Proxy提供了用於建立動態代理類和代理對象的靜態方法,它也是全部動態代理類的父類。若是在程序中爲一個或多個接口動態的生成實現類。就可使用Proxy來建立動態代理類;若是須要爲一個或多個接口動態地建立實例,也可使用Proxy來建立動態代理實例。

      • 系統生成的每一個代理對象都有一個與之關聯的InvocationHandler對象,定義一個InvocationHandler實現類須要重寫invoke()方法——調用代理對象的全部方法時都會被替換成調用該invoke()方法,Object invoke(Object proxy,Method method,Object[] args)

    • 動態代理和AOP

      • JDK動態代理只能爲接口建立動態代理

      • 採用動態代理能夠很是靈活的實現解耦,一般都是爲指定的目標對象生成動態代理

      • 這種動態代理在AOP(Aspect Orient Programming)中被稱爲AOP代理,AOP代理包含目標對象的所有方法,能夠替代目標對象。可是兩者存在差別:AOP代理裏的方法能夠在執行目標方法先後插入一些通用處理

  5. 反射和泛型

    • 泛型和Class

      • 使用Class<T>泛型能夠避免強制類型轉換

      • 對象工廠

    • 使用反射來獲取泛型信息

      • 經過指定類對應的Class對象,能夠得到類中的全部Field及其類型:

        Class<?> a=f.getType()//普通類型

      • 獲取泛型類型:Type gType=f.getGenericType()

      • ParameterizedType對象

        1. getRawType():返回沒有泛型信息的原始類型

        2. getActualTypeArguments():返回泛型參數的類型

相關文章
相關標籤/搜索