Java Reflect 反射機制

Java Reflect 反射機制

類字節(jié)碼文件是在硬盤上存儲的,是一個個的.class文件。我們在new一個對象時,JVM會先把字節(jié)碼文件的信息讀出來放到內(nèi)存中,第二次用時,就不用在加載了,而是直接使用之前緩存的這個字節(jié)碼信息

字節(jié)碼的信息包括:類名、聲明的方法、聲明的字段等信息。在Java中“萬物皆對象”,這些信息當然也需要封裝一個對象,這就是Class類、Method類、Field類。

通過Class類、Method類、Field類等等類可以得到這個類型的一些信息,甚至可以不用new關(guān)鍵字就創(chuàng)建一個實例,可以執(zhí)行一個對象中的方法,設(shè)置或獲取字段的值,這就是反射技術(shù)。

  1. Class類
    1. 獲取Class對象的三種方式
      Java中有一個Class類用于代表某一個類的字節(jié)碼。

      1. Java提供了三種方式獲取類的字節(jié)碼
        1. Class.forName("")方法用于加載某個類的字節(jié)碼到內(nèi)存中,并使用class對象進行封裝
        2. 類名.class
        3. 對象.getClass()
        /**
         * 加載類的字節(jié)碼的3種方式
         * @throws ClassNotFoundException
         */
        @Test
        public void test() throws ClassNotFoundException {
            // 方式一
            Class clazz1 = Class.forName("cn.huangmp.java.api.reflect.Person");
            // 方式二
            Class clazz2 = Person.class;
        
            // JVM會先把字節(jié)碼文件的信息讀出來放到內(nèi)存中,第二次用時,就不用在加載了,
            // 而是直接使用之前緩存的這個字節(jié)碼信息。
            // clazz1 == clazz2 : true
            System.out.println("clazz1 == clazz2 : " + (clazz1 == clazz2));
        
            // 方式三
            Person p1 = new Person();
            Class clazz3 = p1.getClass();
        
            System.out.println("clazz3 == clazz2 : " + (clazz3 == clazz2));
        }
        
    2. 通過Class類獲取類型的一些信息

      1. getName()類的名稱(全名,全限定名)
      2. getSimpleName()類的的簡單名稱(不帶包名)
      3. getModifiers(); 類的的修飾符
      4. 創(chuàng)建對象 無參數(shù)構(gòu)造創(chuàng)建對象 newInstance()
      5. 獲取指定參數(shù)的構(gòu)造器對象,并可以使用Constructor對象創(chuàng)建一個實例 Constructor<T> getConstructor(Class<?>... parameterTypes)
      /**
       * 通過Class對象獲取類的一些信息
       * @throws Exception
       */
      @Test
      public void test2() throws Exception {
          Class clazz1 = Class.forName("cn.huangmp.java.api.reflect.Person");
          // 獲取類的名稱
          String name = clazz1.getName();
          System.out.println(name);
          // 獲取類的簡單名稱
          System.out.println(clazz1.getSimpleName()); // Person
          // 獲取類的修飾符
          int modifiers = clazz1.getModifiers();
          System.out.println(modifiers);
      
          // 通過class對象找到所有的構(gòu)造方法
          Constructor[] constructors = clazz1.getConstructors();
          for( Constructor constructor : constructors){
              System.out.println("    " + constructor);
          }
      
          // 通過class對象找到所有的構(gòu)造方法,包括私有方法
          Constructor[] declaredConstructors = clazz1.getDeclaredConstructors();
          for( Constructor constructor : declaredConstructors){
              System.out.println("    " + constructor);
          }
      
          // 構(gòu)建對象(默認調(diào)用無參數(shù)構(gòu)造.)
          Object ins = clazz1.newInstance();
          Person p = (Person) ins;
          System.out.println(p);
          // 獲取指定參數(shù)的構(gòu)造函數(shù)
          Constructor<?> con = clazz1.getConstructor(String.class, int.class);
          // 使用Constructor創(chuàng)建對象.
          Object p1 = con.newInstance("jack", 12);
          System.out.println(((Person) p1).getName());
      
          // 通過私有構(gòu)造方法創(chuàng)建對象
          Constructor constructor = clazz1.getDeclaredConstructor(String.class, int.class, int.class);
          // 設(shè)置構(gòu)造方法的訪問權(quán)限(暴力反射)
          constructor.setAccessible(true);
          Person p2 = (Person) constructor.newInstance("jj", 20, 1);
          System.out.println("p2.name = " + p2.getName());
      }
      
    3. 通過Class類獲取類型中的方法的信息
      1.獲取公共方法包括繼承的父類的方法 getMethods()返回一個數(shù)組,元素類型是Method
      2.獲取指定參數(shù)的公共方法 getMethod("setName", String.class);
      3.獲得所有的方法,包括私有 Method[] getDeclaredMethods()
      4.獲得指定參數(shù)的方法,包括私有 Method getDeclaredMethod(String name, Class<?>... parameterTypes)

      /**
       * 獲取公有方法.
       * @throws Exception
       */
      @Test
      public void test3() throws Exception {
          Class clazz1 = Class.forName("cn.huangmp.java.api.reflect.Person");
          // 1.獲取非私用方法(包括父類繼承的方法)
          Method[] methods = clazz1.getMethods();
          System.out.println(methods.length);
          for (Method m : methods) {
              // System.out.println(m.getName());
              if ("eat".equals(m.getName())) {
                  m.invoke(clazz1.newInstance(), null);
              }
              System.out.println("    " + m.getName());
          }
      }
      
      /**
       * 獲取指定方法簽名的方法
       *
       * @throws Exception
       */
      public void test4() throws Exception {
          Class clazz1 = Class.forName("cn.huangmp.java.api.reflect.Person");
          // 獲取指定名稱的函數(shù)
          // 第一個參數(shù)是方法名, 第二個參數(shù)是形參列表的數(shù)據(jù)類型
          Method method1 = clazz1.getMethod("toString", null);
          // 執(zhí)行方法
          // 第一個參數(shù): 方法的調(diào)用者(對象),第二個參數(shù): 方法執(zhí)行的第二個參數(shù)
          method1.invoke(new Person(), null);
      }
      
      /**
       * 獲取指定方法名且有參數(shù)的方法
       *
       * @throws Exception
       */
      @Test
      public void test5() throws Exception {
          Class clazz1 = Class.forName("cn.huangmp.java.api.reflect.Person");
          Method method = clazz1.getMethod("setName", String.class);
          method.invoke(new Person(), "包子");
      }
      
      /**
       * 獲取指定方法名,參數(shù)列表為空的方法.
       *
       * @throws Exception
       */
      @Test
      public void test6() throws Exception {
          Class clazz1 = Class.forName("cn.huangmp.java.api.reflect.Person");
          // 獲取指定名稱的函數(shù)
          Method method1 = clazz1.getMethod("sayHello", null);
          method1.invoke(new Person(), null);
      }
      
      /**
       * 反射靜態(tài)方法
       * @throws Exception
       */
      @Test
      public void test8() throws Exception {
          Class clazz1 = Class.forName("cn.huangmp.java.api.reflect.Person");
          Method method = clazz1.getMethod("sayHi", null);
          method.invoke(null, null);
      }
      
    4. 通過Class類獲取類型中的字段的信息

      1. 獲取公共字段 Field[] getFields()
      2. 獲取指定參數(shù)的公共字段 Field getField(String name)
      3. 獲取所有的字段 Field[] getDeclaredFields()
      4. 獲取指定參數(shù)的字段,包括私用 Field getDeclaredField(String name)
      /**
       * 獲取公有的字段
       */
      @Test
      public void test9() throws Exception {
          Class clazz1 = Class.forName("cn.huangmp.java.api.reflect.Person");
          Field[] fields = clazz1.getFields();
          Person p = new Person();
          System.out.println(fields.length);
          for (Field f : fields) {
              System.out.println(f.getName());
              if ("name".equals(f.getName())) {
                  System.out.println(f.getType().getName());
                  f.set(p, "jack");
              }
          }
          System.out.println(p.getName());
      }
      
      /**
       * 獲取私有的字段
       * @throws Exception
       */
      @Test
      public void test10() throws Exception {
          Class clazz1 = Class.forName("cn.huangmp.java.api.reflect.Person");
          Field field = clazz1.getDeclaredField("age");
          System.out.println(field.getName());
          field.setAccessible(true);
          Person p = new Person();
          field.set(p, 100);
          System.out.println(p.getAge());
      }
      
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,653評論 18 399
  • 學習Android的同學注意了?。?!學習過程中遇到什么問題或者想獲取學習資源的話,歡迎加入Android學習交流群...
    kingZXY2009閱讀 353評論 0 0
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,545評論 19 139
  • 《寫給十年后的自己》 親愛的自己,你好,見字如面! 十年后的你會變成什么樣呢,我很期待,一大早去樓下等你,我知道每...
    霜霜_b33a閱讀 490評論 0 0
  • 周末有一項作業(yè),語文老師用心良苦,讓孩子們寫一篇五十字的讀后感,傳在班級QQ群里。我知道兒子是不看書的,那么這...
    ganweif閱讀 220評論 0 0

友情鏈接更多精彩內(nèi)容