12 反射

反射機制:前提:jvm已經(jīng)加載這個類,通過一個抽象的類名能夠在自己記憶(加載類的內(nèi)存)中找到相匹配的類的具體信息

  • JAVA reflection
    反射機制允許程序在執(zhí)行期借助于Reflection API取得任何類的內(nèi)部信息窗悯,并能直接操作任意對象的內(nèi)部屬性及方法

Java反射機制提供的功能
在運行時判斷任意一個對象所屬的類
在運行時構(gòu)造任意一個類的對象
在運行時判斷任意一個類所具有的成員變量和方法
在運行時調(diào)用任意一個對象的成員變量和方法
生成動態(tài)代理

反射相關(guān)的主要API:
java.lang.Class:代表一個類
java.lang.reflect.Method:代表類的方法
java.lang.reflect.Field:代表類的成員變量
java.lang.reflect.Constructor:代表類的構(gòu)造方法

Class類

在Object類中定義了以下的方法蒂誉,此方法將被所有子類繼承:
public final Class getClass()
以上的方法返回值的類型是一個Class類挂捅,此類是Java反射的源頭, 實際上所謂反射從程序的運行結(jié)果來看也很好理解脐恩,即:可以通過對象反射求出類的名稱

通過Class類反射可以得到的信息:某個類的屬性舍肠、方法和構(gòu)造器、某個類到底實現(xiàn)了哪些接口呵燕。

實例化Class類對象的四種方法

  1. 前提:若已知具體的類棠绘,通過類的class屬性獲取,該方法最為安全可靠再扭,程序性能最高
    實例:Class clazz = String.class;
  2. 前提:已知某個類的實例氧苍,調(diào)用該實例的getClass()方法獲取Class對象
    實例:Class clazz = “www.xyd.com”.getClass();
  3. 前提:已知一個類的全類名,且該類在類路徑下泛范,可通過Class類的靜態(tài)方法forName()獲取让虐,可能拋出ClassNotFoundException,最常用的方法
    實例:Class clazz = Class.forName(“java.lang.String”);
  4. 其他方式(不做要求)
    ClassLoader cl = this.getClass().getClassLoader();
    Class clazz4 = cl.loadClass(“類的全類名”);

通過反射調(diào)用類的完整結(jié)構(gòu):
通過反射可以取得:

  1. 獲得實現(xiàn)的所有接口
Class clazz = Class.forName("com.ying.javaBase.Student1"); // 通過包名.類名的字符串罢荡,獲取指定類的class實例
Class[] interfaces = clazz.getInterfaces(); // 獲取當前類的所有接口
      for (Class anInterface : interfaces) {
        System.out.println("接口: " + anInterface.getName());
      }
輸出:
接口: com.ying.javaBase.Move
接口: com.ying.javaBase.Study
  1. 獲取所繼承的父類
Class clazz = Class.forName("com.ying.javaBase.Student1"); // 通過包名.類名的字符串赡突,獲取指定類的class實例
Class superClazz = clazz.getSuperclass(); // 獲取父類
System.out.println("父類: " + superClazz.getName());
輸出:
父類: com.ying.javaBase.Person1
  1. 獲取全部的構(gòu)造器
    public Constructor<T>[] getConstructors()
    返回此 Class 對象所表示的類的所有public構(gòu)造方法。
    public Constructor<T>[] getDeclaredConstructors()
    返回此 Class 對象表示的類聲明的所有構(gòu)造方法柠傍。包括私有和公有
    Constructor類中:
    取得修飾符: public int getModifiers();
    取得方法名稱: public String getName();
    取得參數(shù)的類型:public Class<?>[] getParameterTypes();
//測試獲取類的所有構(gòu)造方法麸俘,包括公有和私有
      Constructor[] cons1 = clazz.getDeclaredConstructors();
      for (Constructor con : cons1) {
        System.out.println("---------------------------");
        System.out.println("構(gòu)造方法名稱: " + con.getName());//取得方法名稱
        //返回修飾符,返回數(shù)字1代表public惧笛,返回數(shù)字2,代表private
        System.out.println("構(gòu)造方法" + con.getName() + "的修飾符名稱: " + con.getModifiers()); //取得方法修飾符
        for (Class parameterType : con.getParameterTypes()) {
          System.out.println("參數(shù)類型之一是: " +parameterType.getName());
        }
        System.out.println("---------------------------");
      }
輸出:
---------------------------
構(gòu)造方法名稱: com.ying.javaBase.Student1
構(gòu)造方法com.ying.javaBase.Student1的修飾符名稱: 1
---------------------------
---------------------------
構(gòu)造方法名稱: com.ying.javaBase.Student1
構(gòu)造方法com.ying.javaBase.Student1的修飾符名稱: 2
參數(shù)類型之一是: java.lang.String
參數(shù)類型之一是: int
---------------------------
---------------------------
構(gòu)造方法名稱: com.ying.javaBase.Student1
構(gòu)造方法com.ying.javaBase.Student1的修飾符名稱: 1
參數(shù)類型之一是: java.lang.String
---------------------------
  • 用反射的構(gòu)造方法創(chuàng)建對象
  1. 獲取默認的無參的構(gòu)造方法
Class clazz = Class.forName("com.ying.javaBase.Student1"); // 通過包名.類名的字符串从媚,獲取指定類的class實例
 //通過反射的構(gòu)造方法來創(chuàng)建對象
Object o = clazz.newInstance();//相當于調(diào)用Student1的無產(chǎn),公有的構(gòu)造方法
Student1 stu = (Student1) o;

java.lang.reflect.Constructor:代表類的構(gòu)造方法

  1. 獲取指定的公有的構(gòu)造方法來創(chuàng)建對象
Constructor c = clazz.getConstructor(String.class);//指定獲取有一個參數(shù)為String類型的患整,公有的構(gòu)造方法//
Student1 stu1 = (Student1) c.newInstance("第一中學");
System.out.println(stu1.school);
  1. 獲取私有的構(gòu)造方法來創(chuàng)建對象
Constructor c = clazz.getDeclaredConstructor(String.class, int.class);//指定獲取帶有兩個參數(shù)的構(gòu)造方法
      c.setAccessible(true);//解除私有的封裝拜效,便可以強制調(diào)用私有構(gòu)造方法
      Student1 stu = (Student1) c.newInstance("張三", 12);
  • 通過反射獲取所有的方法
    public Method[] getDeclaredMethods()
    返回此Class對象所表示的類或接口的全部方法喷众,不包括父類的
    public Method[] getMethods()
    返回此Class對象所表示的類或接口的public的方法,包括父類的

    Method類中:
    public Class<?> getReturnType()取得全部的返回值
    public Class<?>[] getParameterTypes()取得全部的參數(shù)
    public int getModifiers()取得修飾符

  • 通過反射獲取類的屬性

public Field[] getFields()
返回此Class對象所表示的類或接口的public的Field紧憾。到千,包括父類的
public Field[] getDeclaredFields()
返回此Class對象所表示的類或接口的全部Field。不包括父類的

Field方法中:
public int getModifiers() 以整數(shù)形式返回此Field的修飾符
public Class<?> getType() 得到Field的屬性類型
public String getName() 返回Field的名稱赴穗。

  • 通過反射獲取類的包
    Package getPackage()

java.lang.reflect.Method:代表類的方法

  • 通過反射獲取指定方法
Constructor con = clazz.getConstructor();//獲取無參構(gòu)造
      Object obj = con.newInstance();//使用無參構(gòu)造創(chuàng)建對象
      Student1 stu = (Student1)obj;
      //得到名稱是公有的setInfo憔四,參數(shù)是string string的方法
      Method m = clazz.getMethod("setInfo", String.class, String.class);
      m.invoke(stu, "張三", "第一中學");//參數(shù)一對象,后面的參數(shù)是調(diào)用當前方法的實際參數(shù)
      //如果想要調(diào)用私有方法
      Method m1 = clazz.getDeclaredMethod("test", String.class);
      m1.setAccessible(true); //解除私有的封裝
      m1.invoke(stu, "李四");

      //調(diào)用重載方法
      Method m2 = clazz.getMethod("setInfo", int.class);
      m2.invoke(stu, 2);

      //有返回值的方法
      Method m3 = clazz.getMethod("getSchool");//獲取方法名為getSchool般眉,沒有參數(shù)的方法
      System.out.println(m3.invoke(stu));

java.lang.reflect.Field:代表類的成員變量

Constructor con = clazz.getConstructor();
      Student1 stu = (Student1) con.newInstance();
      Field f = clazz.getDeclaredField("school");//獲取名稱為school的屬性
      f.setAccessible(true);
      f.set(stu, "第三中學");//對stu對象的school屬性設(shè)置值
      String school = (String) f.get(stu);
      System.out.println(school);

java動態(tài)代理

Proxy :專門完成代理的操作類了赵,是所有動態(tài)代理類的父類。通過此類為一個或多個接口動態(tài)地生成實現(xiàn)類甸赃。
創(chuàng)建一個動態(tài)代理類所對應的Class對象

  • 動態(tài)代理步驟:
    1.創(chuàng)建一個實現(xiàn)接口InvocationHandler的類柿汛,它必須實現(xiàn)invoke方法,以完成代理的具體操作埠对。
public class ProxyDemo implements InvocationHandler {

    Object obj;//被代理的對象

    public ProxyDemo(Object obj) {
        this.obj = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println(method.getName() + "方法開始執(zhí)行");
        Object result = method.invoke(this.obj, args);//執(zhí)行的是指定代理對象的指定方法
        System.out.println(method.getName() + "方法執(zhí)行完畢");


        return result;
    }
}

2.創(chuàng)建被代理的類以及接口
/**

  • 注意:如果一個對象想要通過Proxy.newProxyInstance方法被代理络断,
  • 那么這個對象的類一定要有相應的接口
  • 就像本類中的ITestDemo接口和實現(xiàn)類TestDemoImpl
    */
public interface ITestDemo {
    void test1();
    void test2();

}
public class TestDemoImpl implements ITestDemo{
    @Override
    public void test1() {
        System.out.println("執(zhí)行test1()方案");
    }

    @Override
    public void test2() {
        System.out.println("執(zhí)行test2()方案");
    }
}

3.通過Proxy的靜態(tài)方法
newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 創(chuàng)建一個Subject接口代理
4.通過 Subject代理調(diào)用RealSubject實現(xiàn)類的方法

ITestDemo test = new TestDemoImpl();
 /**
       * 需求:
       * 在執(zhí)行方法前,打印 方法開始執(zhí)行
       * 在執(zhí)行方法后项玛,打印 方法執(zhí)行完畢
       * 打印的方法名和方法保持一致
       */
      InvocationHandler handler = new ProxyDemo(test);
      /**
       * newProxyInstance(ClassLoader, interface, h)
       * 參數(shù)一:ClassLoader: 代理對象的類加載器
       * 參數(shù)二:interface:被代理對象的接口
       * 參數(shù)三:H 代理對象
       * 返回值:成功被代理后的對象
       */
      ITestDemo t = (ITestDemo) Proxy.newProxyInstance(handler.getClass().getClassLoader(), test.getClass().getInterfaces(), handler);
      t.test1();
      System.out.println("-------------");
      t.test2();
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末貌笨,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子稍计,更是在濱河造成了極大的恐慌躁绸,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件臣嚣,死亡現(xiàn)場離奇詭異净刮,居然都是意外死亡,警方通過查閱死者的電腦和手機硅则,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門淹父,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人怎虫,你說我怎么就攤上這事暑认。” “怎么了大审?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵蘸际,是天一觀的道長。 經(jīng)常有香客問我徒扶,道長粮彤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮导坟,結(jié)果婚禮上屿良,老公的妹妹穿的比我還像新娘。我一直安慰自己惫周,他們只是感情好尘惧,可當我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著递递,像睡著了一般喷橙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上登舞,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天重慢,我揣著相機與錄音,去河邊找鬼逊躁。 笑死,一個胖子當著我的面吹牛隅熙,可吹牛的內(nèi)容都是我干的稽煤。 我是一名探鬼主播,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼囚戚,長吁一口氣:“原來是場噩夢啊……” “哼酵熙!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起驰坊,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤匾二,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后拳芙,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體察藐,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年舟扎,在試婚紗的時候發(fā)現(xiàn)自己被綠了分飞。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡睹限,死狀恐怖譬猫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情羡疗,我是刑警寧澤染服,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站叨恨,受9級特大地震影響柳刮,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一诚亚、第九天 我趴在偏房一處隱蔽的房頂上張望晕换。 院中可真熱鬧,春花似錦站宗、人聲如沸闸准。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽夷家。三九已至,卻和暖如春敏释,著一層夾襖步出監(jiān)牢的瞬間库快,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工钥顽, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留义屏,地道東北人。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓蜂大,卻偏偏與公主長得像闽铐,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子奶浦,可洞房花燭夜當晚...
    茶點故事閱讀 43,490評論 2 348

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