JAVA高級編程之類加載-反射-動態(tài)代理

Java高級編程之類加載

當(dāng)程序要使用某個類時却嗡,如果該類還未被加載到內(nèi)存中闰渔,則系統(tǒng)會通過加載,連接秉颗,初始化三步來實現(xiàn)對這個類進行初始化痢毒。

  1. 加載
    就是指將class文件讀入內(nèi)存,并為之創(chuàng)建一個Class對象蚕甥。
    任何類被使用時系統(tǒng)都會建立一個Class對象哪替。
  2. 連接
  3. 驗證 是否有正確的內(nèi)部結(jié)構(gòu),并和其他類協(xié)調(diào)一致
  4. 準(zhǔn)備 負責(zé)為類的靜態(tài)成員分配內(nèi)存菇怀,并設(shè)置默認初始化值
  5. 解析 將類的二進制數(shù)據(jù)中的符號引用替換為直接引用
  6. 初始化 就是我們以前講過的初始化步驟

類初始化時機

在以下情況下會對類進行初始化

  • 創(chuàng)建類的實例
  • 訪問類的靜態(tài)變量凭舶,或者為靜態(tài)變量賦值
  • 調(diào)用類的靜態(tài)方法
  • 使用反射方式來強制創(chuàng)建某個類或接口對應(yīng)java.lang.Class對象
  • 初始化某個類的子類
  • 直接使用java.exe命令來運行某個主類

類加載器

類加載器的作用

  • 負責(zé)將.class文件加載到內(nèi)在中,并為之生成對應(yīng)的Class對象爱沟。
  • 雖然我們不需要關(guān)心類加載機制帅霜,但是了解這個機制我們就能更好的理解程序的運行

類加載的組成

  1. Bootstrap ClassLoader 根類加載器
  2. Extension ClassLoader 擴展類加載器
  3. Sysetm ClassLoader 系統(tǒng)類加載器
Bootstrap ClassLoader 根類加載器

也被稱為引導(dǎo)類加載器,負責(zé)Java核心類(支持java運行類)的加載
比如System,String等呼伸。在JDK中JRE的lib目錄下rt.jar文件中

Extension ClassLoader 擴展類加載器

負責(zé)JRE的擴展目錄中jar包的加載身冀。
在JDK中JRE的lib目錄下ext目錄

Sysetm ClassLo*ader 系統(tǒng)類加載器

加載我們自己寫的項目
負責(zé)在JVM啟動時加載來自java命令的class文件,以及classpath環(huán)境變量所指定的jar包和類路徑

Java高級編程之反射

通過類加載我們拿到了class文件括享,接下來就是使用反射來玩搂根。

java反射機制

JAVA反射機制是在運行狀態(tài)中,對于任意一個類铃辖,都能夠知道這個類的所有(包括private)屬性和方法剩愧;對于任意一個對象,都能夠調(diào)用它的任意一個方法和屬性娇斩;這種動態(tài)獲取的信息以及動態(tài)調(diào)用對象的方法的功能稱為java語言的反射機制仁卷。
拿到class文件就可以去用它,而不是java文件犬第。
要想解剖一個類,必須先要獲取到該類的字節(jié)碼文件對象锦积。而解剖使用的就是Class類中的方法.所以先要獲取到每一個字節(jié)碼文件對應(yīng)的Class類型的對象.
總之就是通過class文件對象,去使用該文件的成員變量歉嗓,成員方法充包,構(gòu)造方法。

如何獲取Class類型的對象

一個Class類包含:

  1. 成員變量 Field
  2. 構(gòu)造方法 Constructor
  3. 成員方法 Method

Object類中的getClass()方法

Person p=new Person()
Class c=p.getClass()
Person p2=new Person()
Class c2=p2.getClass()
試問(c1==c2)結(jié)果是true還是false遥椿?
通過對象獲取的是Class文件對象(字節(jié)碼文件對象)Person就一個Class文件所以答案為true。

數(shù)據(jù)類型的靜態(tài)屬性class

Person.class String.class

Class類中的靜態(tài)方法

//path必須寫全路徑
Class.forName(path);

一般到底使用誰淆储?
A.自己玩任選一種冠场,第二種更方便
B. 開發(fā)選第三種因為第三種是一個字符串而不是一個具體的類名,這樣我們就可以把這個字符串配置到配置文件中本砰。

通過反射獲取構(gòu)造方法并使用

  1. 獲得字節(jié)碼文件對象
    Class c =Class.forName("cn.zts.Person");

  2. 獲取構(gòu)造方法

     //public Constructor[] getConstructors() //獲取公共的構(gòu)造方法
     //public Constructor[] getDeclaredConstructors()  //獲取所有的構(gòu)造方法包括泛型
     //獲取單個構(gòu)造方法(只能獲取公共的)
     // public Constructor getConstructor(Class<?>... paramterType)
     //參數(shù)表示的是:你要獲取構(gòu)造方法的構(gòu)造參數(shù)個數(shù)及數(shù)據(jù)類型的CLass字節(jié)碼文件對象.如String.class
     Constructor conn=c.getConstructor();返回的是構(gòu)造方法的對象
     //通過該對象創(chuàng)建該類的實例碴裙。newInstance()  
     Object object=conn.newInstance(Object...initarge);
    

以上內(nèi)容就相當(dāng)于Person object=new Person();

暴力訪問

獲取私有的構(gòu)造方法

Constructor con=c.getDeclaredConstructor(String.class);  

//如果直接訪問會報非法的訪問異常。所以此時我們需要暴力訪問
con.setAccessible(true);//值為true時指示反射的對象在使用時取消java語言訪問檢查
Object obj=con.newInstance("zts");

通過反射獲取成員變量并且使用

  1. 獲得字節(jié)碼文件對象
    Class c =Class.forName("cn.zts.Person");
  2. 獲取成員變量
    c.getFields()//獲取所有的公共成員變量
    c.getDeclaredFields()//獲取所有的成員變量
    //獲取單個成員變量
    Field addressField=c.getField("address");
    //通過無參構(gòu)造方法創(chuàng)建對象
    Constructor con=c.getConstructor();
    Object obj=con.newInstance();
  3. 給成員變量賦值
    //public void set(Object obj,Object value);
    //將指定對象變量上找Field,對象表示的字段設(shè)置為指定的新值.
    addressField.set(obj,"北京");

set方法的意思就是給obj對象的addressField字段設(shè)置值為北京舔株。

暴力訪問

獲取私有的成員變量
Field addressField=c.getDeclaredField("address");
//如果直接訪問會報非法的訪問異常莺琳。所以此時我們需要暴力訪問
con.setAccessible(true);//值為true時指示反射的對象在使用時取消java語言訪問檢查

通過反射獲取成員方法并且使用

  1. 獲得字節(jié)碼文件對象
    Class c =Class.forName("cn.zts.Person");
  2. 獲取成員方法
    //獲取所有成員方法、
    Method[] methods=c.getMethods()//獲取自己包括父親的所有公共方法载慈。
    Method[] methods=c.getDeclaredMethods()//獲取自己所有的方法
    //通過無參構(gòu)造方法創(chuàng)建對象
    Constructor con=c.getConstructor();
    Object obj=con.newInstance();
    //獲取單個方法并且使用getMethod(String name,Class<?> ...paraterType)
    Method m1=c.getMethod("show");
    //obj.m1()//錯誤
    //使用該方法--invoke(Object object,Object...args)惭等;
    m1.invoke(obj);//調(diào)用obj對象的m1方法。

eg:

    // 獲取字節(jié)碼文件對象
    Class c = Class.forName("cn.itcast_01.Person");

    // 獲取所有的方法
    // Method[] methods = c.getMethods(); // 獲取自己的包括父親的公共方法
    // Method[] methods = c.getDeclaredMethods(); // 獲取自己的所有的方法
    // for (Method method : methods) {
    // System.out.println(method);
    // }

    Constructor con = c.getConstructor();
    Object obj = con.newInstance();

    /*
     * Person p = new Person(); p.show();
     */

    // 獲取單個方法并使用
    // public void show()
    // public Method getMethod(String name,Class<?>... parameterTypes)
    // 第一個參數(shù)表示的方法名办铡,第二個參數(shù)表示的是方法的參數(shù)的class類型
    Method m1 = c.getMethod("show");
    // obj.m1(); // 錯誤
    // public Object invoke(Object obj,Object... args)
    // 返回值是Object接收,第一個參數(shù)表示對象是誰辞做,第二參數(shù)表示調(diào)用該方法的實際參數(shù)
    m1.invoke(obj); // 調(diào)用obj對象的m1方法

    System.out.println("----------");
    // public void method(String s)
    Method m2 = c.getMethod("method", String.class);
    m2.invoke(obj, "hello");
    System.out.println("----------");

    // public String getString(String s, int i)
    Method m3 = c.getMethod("getString", String.class, int.class);
    Object objString = m3.invoke(obj, "hello", 100);
    System.out.println(objString);
    // String s = (String)m3.invoke(obj, "hello",100);
    // System.out.println(s);
    System.out.println("----------");

    // private void function()
    Method m4 = c.getDeclaredMethod("function");
    m4.setAccessible(true);
    m4.invoke(obj);

通過反射越過泛型檢查

比如。我們有個集合ArrayList<Integer> list我們需要給他添加個字符串類型的數(shù)據(jù)

創(chuàng)建集合對象  
ArrayList<Integer> array = new ArrayList<Integer>();

    // array.add("hello");
    // array.add(10);

    Class c = array.getClass(); // 集合ArrayList的class文件對象
    Method m = c.getMethod("add", Object.class);

    m.invoke(array, "hello"); // 調(diào)用array的add方法寡具,傳入的值是hello
    m.invoke(array, "world");
    m.invoke(array, "java");

    System.out.println(array);

java高級編程之動態(tài)代理

  1. 代理:本來應(yīng)該自己做的事情秤茅,卻請了別人來做,被請的人就是代理對象童叠。
  2. 舉例:春季回家買票讓人代買
  3. 動態(tài)代理:在程序運行過程中產(chǎn)生的這個對象

而程序運行過程中產(chǎn)生對象其實就是我們剛才反射講解的內(nèi)容框喳,所以,動態(tài)代理其實就是通過反射來生成一個
在Java中java.lang.reflect包下提供了一個Proxy類和一個InvocationHandler接口厦坛,通過使用這個類和接口就可以生成動態(tài)代理對象五垮。JDK提供的代理只能針對接口做代理。我們有更強大的代理cglib

Proxy類中的方法創(chuàng)建動態(tài)代理類對象

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
最終會調(diào)用InvocationHandler的方法(InvocationHandler是個接口粪般,我們需要自定義一個類實現(xiàn)這個接口)
InvocationHandler
Object invoke(Object proxy,Method method,Object[] args)

eg:我們在如下例子實現(xiàn)在增刪改查中添加權(quán)限校驗和日志記錄用動態(tài)代理實現(xiàn)
  • StudentDao.java

      public interface StudentDao {
      public abstract void login();
      public abstract void regist();
      }  
    
  • StudentDaoImp.java

      public class StudentDaoImpl implements StudentDao {
    
      @Override
      public void login() {
        System.out.println("登錄功能");
      }
    
      @Override
      public void regist() {
           System.out.println("注冊功能");
      }
    
      }
    
  • MyInvocationHandler.java

      public class MyInvocationHandler implements InvocationHandler {
       private Object target; // 目標(biāo)對象
    
       public MyInvocationHandler(Object target) {
          this.target = target;
       }
    
      @Override
      public Object invoke(Object proxy, Method method, Object[] args)
          throws Throwable {
      System.out.println("權(quán)限校驗");
      Object result = method.invoke(target, args);
      System.out.println("日志記錄");
      return result; // 返回的是代理對象
      }
      }
    
  • Test.java

      public class Test {
      public static void main(String[] args) {
      UserDao ud = new UserDaoImpl();
         ud.add();
         ud.delete();
         ud.update();
          ud.find();
         System.out.println("-----------");
         // 我們要創(chuàng)建一個動態(tài)代理對象
         // Proxy類中有一個方法可以創(chuàng)建動態(tài)代理對象
         // public static Object newProxyInstance(ClassLoader    loader,Class<?>[]
         // interfaces,InvocationHandler h)
        // 我準(zhǔn)備對ud對象做一個代理對象
        MyInvocationHandler handler = new MyInvocationHandler(ud);
        UserDao proxy = (UserDao) Proxy.newProxyInstance(ud.getClass()
              .getClassLoader(), ud.getClass().getInterfaces(), handler);
          proxy.add();
          proxy.delete();
          proxy.update();
          proxy.find();
    
      }
      }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末拼余,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子亩歹,更是在濱河造成了極大的恐慌匙监,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件小作,死亡現(xiàn)場離奇詭異亭姥,居然都是意外死亡,警方通過查閱死者的電腦和手機顾稀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門达罗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人静秆,你說我怎么就攤上這事粮揉。” “怎么了抚笔?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵扶认,是天一觀的道長。 經(jīng)常有香客問我殊橙,道長辐宾,這世上最難降的妖魔是什么狱从? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮叠纹,結(jié)果婚禮上季研,老公的妹妹穿的比我還像新娘。我一直安慰自己誉察,他們只是感情好与涡,可當(dāng)我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著冒窍,像睡著了一般递沪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上综液,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天款慨,我揣著相機與錄音,去河邊找鬼谬莹。 笑死檩奠,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的附帽。 我是一名探鬼主播埠戳,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蕉扮!你這毒婦竟也來了整胃?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤喳钟,失蹤者是張志新(化名)和其女友劉穎屁使,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體奔则,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡蛮寂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了易茬。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片酬蹋。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖抽莱,靈堂內(nèi)的尸體忽然破棺而出范抓,到底是詐尸還是另有隱情,我是刑警寧澤食铐,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布匕垫,位于F島的核電站,受9級特大地震影響璃岳,放射性物質(zhì)發(fā)生泄漏年缎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一铃慷、第九天 我趴在偏房一處隱蔽的房頂上張望单芜。 院中可真熱鬧,春花似錦犁柜、人聲如沸洲鸠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽扒腕。三九已至,卻和暖如春萤悴,著一層夾襖步出監(jiān)牢的瞬間瘾腰,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工覆履, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蹋盆,地道東北人。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓硝全,卻偏偏與公主長得像栖雾,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子伟众,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法析藕,類相關(guān)的語法,內(nèi)部類的語法凳厢,繼承相關(guān)的語法账胧,異常的語法,線程的語...
    子非魚_t_閱讀 31,639評論 18 399
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理数初,服務(wù)發(fā)現(xiàn)找爱,斷路器,智...
    卡卡羅2017閱讀 134,660評論 18 139
  • 一:java概述:1泡孩,JDK:Java Development Kit车摄,java的開發(fā)和運行環(huán)境,java的開發(fā)工...
    ZaneInTheSun閱讀 2,654評論 0 11
  • 命運的禮物晚一點兒仑鸥,慢一點兒吮播,波折一點兒,只是為了用心扎個漂亮的蝴蝶結(jié)眼俊。 別總抱怨自己命運多舛意狠。 世界那么大,多的...
    G寵兒閱讀 409評論 0 2
  • 【總裁的人力資源管理202】”用人五步法” "識人"疮胖,人海茫茫环戈,如何尋找到對的人是機緣也是策略闷板。機緣是與Ta尋找的...
    季元Irene心語教練閱讀 505評論 0 0