反射機制入門

這是關於反射機制的一篇筆記。 視頻教程地址

  • 概念:將類的各個組成部分封裝爲其他對象,就是反射機制

  • 好處:

    • 可以在程序運行中操作這些對象
    • 可以解耦,提高程序的可擴展性。
  • 獲取class對象的方式:

    1. Class.forName("全類名"):將字節碼文件加載進內存,返回class對象。

      • 多用於配置文件,將類名定義在配置文件中,讀取文件,加載類。
    2. 類名.class 通過類名的屬性class獲取

      • 多用於參數的傳遞
    3. 對象.getClass()getClass()方法在Object類中定義着。

      • 多用於對象的獲取字節碼的方式
    4. 同一字節碼文件(*.class)在一次程序運行過程中,只會被加載一次,不論通過哪一種方式獲取的class對象都是同一個。

    5. 代碼

      //1.Class.forName("全類名");
      Class cls1 = Class.forName("com.qmh.domain.Person");
      System.out.println(cls1);
      //2.類名.class
      Class cls2 = Person.class;
      System.out.println(cls2);
      //3.對象.getClass()
      Person p = new Person();
      Class cls3 = p.getClass();
      System.out.println(cls3);
      
  • Class對象功能:

    • 獲取成員變量們

      • public Field[] getFields() :獲取所有public修飾的成員變量
      • public Field getField(String name)::獲取指定名稱的public修飾的成員變量
      • public Field[] getDeclaredFields():獲取所有的成員變量,不考慮修飾符
      • public Field getDeclaredField(String name):獲取指定名稱的成員變量,不考慮修飾符
    • 獲取構造方法們

      • public Constructor<?>[] getConstructors()
      • public Constructor<T> getConstructor(類<?>... parameterTypes)
      • public Constructor<?>[] getDeclaredConstructors()
      • public Constructor<T> getDeclaredConstructor(類<?>... parameterTypes)
    • 獲取成員方法們

      • public Method[] getMethods()
      • public Method getMethod(String name,類<?>... parameterTypes)
      • public Method[] getDeclaredMethods()
      • public Method getDeclaredMethod(String name,類<?>... parameterTypes)
    • 獲取類名

      • String getName()
      //獲取類名
      String className = personClass.getName();
      System.out.println(className);
      
  • Field:成員變量

    • 操作:

      • 獲取值 public Object get(Object obj)
      • 設置值 public void set(Object obj,Object value)
      • 忽略訪問權限修飾符的安全檢查 name.setAccessible(true); //暴力反射
    • 代碼:

      //1.獲取Person的Class對象
              Class<Person> personClass = Person.class;
              //2.獲取成員變量們
              Field[] fields = personClass.getFields();
              for(Field field:fields){
                  System.out.println(field);
              }
              System.out.println("--------------");
              //3.獲取指定名稱的成員變量
              Field a = personClass.getField("a");
              //獲取a的值
              Person p = new Person();
              Object o = a.get(p);
              System.out.println(o);
              //設置a的值
              a.set(p,"張三");
              System.out.println(p);
              System.out.println("--------------");
              //獲取所有的成員變量,不考慮修飾符
              Field[] declaredFields = personClass.getDeclaredFields();
              for(Field declaredField : declaredFields){
                  System.out.println(declaredField);
              }
              // 訪問某個私有成員變量,
              Field name = personClass.getDeclaredField("name");
              //忽略訪問權限符的安全檢查
              name.setAccessible(true); //暴力反射
              Object o1 = name.get(p);
              System.out.println(o1);
              name.set(p,"李四");
              System.out.println(p);
      
  • Constructor:構造方法

    • 創建對象 public T newInstance(Object... initargs)
    • 如果使用空參數構造方法創建對象,操作可以簡化:Class對象的newInstance()方法
    • 代碼:
    //1.獲取Person的Class對象
    Class<Person> personClass = Person.class;
    //獲取某個構造方法
    Constructor<Person> constructor = personClass.getConstructor(String.class, int.class);
    System.out.println(constructor);
    //創建對象
    Person person = constructor.newInstance("張三", 18);
    System.out.println(person);
    System.out.println("--------------");
    //空參構造方法
    Person person2 = personClass.newInstance();
    System.out.println(person2);
    
  • Method 方法對象

    • 執行方法 public Object invoke(Object obj,Object... args)
    • 獲取方法名稱:method.getName()
    • 代碼:
    		//1.獲取Person的Class對象
            Class<Person> personClass = Person.class;
            // 獲取空參方法
            Method eat = personClass.getMethod("eat");
            Person p = new Person();
            //執行方法
            eat.invoke(p);
            //獲取帶參方法 參數:方法名和參數類
            Method eat1 = personClass.getMethod("eat", String.class);
            //執行方法,傳入對象和參數
            eat1.invoke(p, "飯");
            //獲取所有public修飾的方法
            Method[] methods = personClass.getMethods();
            for(Method method:methods){
                System.out.println(method);
                String name = method.getName();
                System.out.println(name);
            }
    
  • 案例:

    • 需求:寫一個“框架”,不能改變該類的任何代碼,可以幫助我們創建任意類的對象,並執行其中任意類的方法

    • 實現:

      1. 配置文件
      2. 反射
    • 步驟

      1. 將需要創建的對象的全類名和需要執行的方法定義在配置文件中
      2. 在程序中加載配置文件
      3. 使用反射技術來加載類文件進內存
      4. 創建對象
      5. 執行方法
    • 配置文件內容:

      className = com.qmh.domain.Student
      methodName = sleep
      
    • 測試代碼:

      public static void main(String[] args) throws Exception {
          //不能改變該類的任何代碼,可以創建任意類的對象,可以執行任意方法
          /*Person p = new Person();
          p.eat();*/
          //1.加載配置文件
          //1.1 創建Properties對象
          Properties pro = new Properties();
          //1.2加載配置文件,轉換爲一個集合
          pro.load(Resources.getResourceAsStream("pro.properties"));
          //2.獲取配置文件中定義的數據
          String className = pro.getProperty("className");
          String methodName = pro.getProperty("methodName");
          //3.加載該類進內存
          Class cls = Class.forName(className);
          //4.創建對象 無參構造函數
          Object o = cls.newInstance();
          //5.獲取方法對象
          Method method = cls.getMethod(methodName);
          //6.執行方法
          method.invoke(o);
      }
      
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章