1. 程式人生 > >關於Java中反射問題的權威解答,歡迎查閱!

關於Java中反射問題的權威解答,歡迎查閱!

1.反射介紹

  • 在執行階段,動態獲取類的資訊和呼叫類的屬性和方法的機制稱為反射機制

2.反射的作用

  • 獲取物件所屬的類(父類,介面)
  • 通過類建立物件
  • 獲取物件所有的屬性和方法(呼叫)
  • 建立代理物件

3.反射採用api(java.lang.reflect)

  • Class:包含類中所有的資訊
    • 通過類載入器在載入過程中為每一個類建立唯一的class物件。

 

  • Class建立的三種方式  

//1.類名.class

        Class clz = Apple.class;

        //2.物件.getClass()

        Class clz2 = apple.getClass();

        //3.類的全限定名稱(全路徑)

        try {

            Class clz3 = Class.forName("test.Apple");

        } catch (ClassNotFoundException e) {

            e.printStackTrace();

        }
  • 建立物件方式
/**

         * 1.呼叫無參構造(若沒有無參構造,或無參構造沒有訪問許可權則建立失敗)

         * 2.介面,抽象類,陣列,基本型別建立失敗

         */

Apple apple = (Apple) clz.newInstance();

apple.eat();

 

  • Field:  封裝了屬性物件
//獲取屬性

        //獲取封裝指定public屬性的field物件

        Field field = clz.getField("weight");

        //System.out.println(field);

        //給屬性賦值    apple.setWeight(12);

        //物件  值

        Apple apple = clz.newInstance();

        field.set(apple, 12);

        //獲取屬性的值

        System.out.println(field.get(apple));

       

       

        //獲取所有的public修飾的屬性(獲取父類的屬性)

        /*Field [] fields = clz.getFields();

        System.out.println(Arrays.toString(fields));*/

       

        //獲取所有的屬性(包含私有的,不能獲取父類)

        Field [] fields = clz.getDeclaredFields();

        System.out.println(Arrays.toString(fields));

       

        //獲取指定屬性(私有的)

        Field f = clz.getDeclaredField("size");

        f.setAccessible(true);

        f.set(apple, 11);

        System.out.println(f.get(apple));

 

  • Method:  封裝方法的物件
//1.獲取public修飾的指定方法

        //Method method = clz.getMethod("show2");

        Method method2 = clz.getMethod("show", String.class);

        //執行方法的呼叫

        method2.invoke(apple, "aaaa");

        //2.獲取所有的public方法(父類的)

        //clz.getMethods();

        //3.獲取所有的方法(私有)

        //clz.getDeclaredMethods();

        //4.獲取指定私有方法

        Method method = clz.getDeclaredMethod("show2");

        method.setAccessible(true);

        method.invoke(apple);

 

  • Constructor:  包含了構造方法的資訊(class獲取)
GetConstructor(Class…paramerType):獲取公共的構造方法

GetConstructors():獲取公共的所有的構造方法

getDeclaredConstructor(Class…paramerType):該類所有構造方法之一(包含私有的)

getDeclaredConstructors():獲取所有的構造方法

//2.獲取有參構造

        //獲取帶有一個String型別引數的構造方法

        Constructor<Apple> constructor = clz.getConstructor(String.class);

        //通過constructor建立物件

        Apple apple = constructor.newInstance("紅色");

        //apple.show();

        /*Constructor<Apple> constructor = clz.getConstructor();//無參構造

        Apple apple = constructor.newInstance();

        System.out.println(apple);*/

       

        //獲取所有的public構造方法

        /*Constructor[] constructors = clz.getConstructors();

        System.out.println(Arrays.toString(constructors));*/

       

        //獲取所有的構造方法(包含私有的)

        /*Constructor<?>[] declaredConstructors = clz.getDeclaredConstructors();

        System.out.println(Arrays.toString(declaredConstructors));*/

       

        //獲取指定構造方法

        Constructor<Apple> constructor2 = clz.getDeclaredConstructor(int.class);

        //授權

        constructor2.setAccessible(true);

        Apple apple2 = constructor2.newInstance(1);

        apple2.show();

 

  • 反射的優點和缺點
    • 優點: 靈活性和擴充套件性,降低了耦合性
    • 缺點:  維護難度大
  • 代理模式
    • 開閉原則: 面向修改關閉,面向擴充套件開放。
    • 代理模式: java語言23種設計模式。(GOF的<<設計模式>>)
    • 設計模式: 經驗,程式碼的擴充套件,鬆耦合。
  • 訪問物件另一種方式。給需要操作的真實物件建立代理物件,通過操作代理物件實現對真實物件的使用,可以實現對真實物件內容擴充套件。
    • 靜態代理:  在編譯期間,為每一個真實物件的類建立代理類
    • 每一個真實物件的方法都要新增增強。
interface Yulequan{

    void play();

    void kongfu();

}



class LiYiFeng implements Yulequan{



    @Override

    public void play() {

        System.out.println("我不會play");

    }



    @Override

    public void kongfu() {

        System.out.println("我不會kongfu");

    }

   

}



//真實物件類

class BaoQiang implements Yulequan{

    @Override

    public void play() {

        System.out.println("我會play");

    }

    @Override

    public void kongfu() {

        System.out.println("我會kongfu");

    }

}

//代理類

class SongZhe implements Yulequan{

    Yulequan bq;

    public SongZhe(Yulequan bq) {

        this.bq = bq;

    }

    @Override

    public void play() {

        System.out.println("開始");

        bq.play();

        System.out.println("結束");

    }

    @Override

    public void kongfu() {

        System.out.println("開始");

        bq.kongfu();

        System.out.println("結束");

    }

}





public class StaticProxy {



    public static void main(String[] args) {

        Yulequan yl = new SongZhe(new LiYiFeng());

        yl.kongfu();

    }



}
  • 動態代理:執行期間,為真實物件建立代理物件的方式。(反射)
    • JDK的動態代理(介面+真正物件的類)
//1.建立目標類物件

       YuLeQuan yl = new BQ();

      

       //2.給目標物件建立代理物件

           //2.1 目標類物件實現同一個介面

           //2.2 代理類物件中需要獲取每一個方法

         

       /*引數:  1.類載入器(用於載入獲取class物件)

        *      2.interfaces:獲取目標物件所有實現的介面(獲取所有方法)

        *      3.invocationhandler:真正遍歷處理每一個需要增強方法地方

        *         invoke方法: 訪問一次interface的方法,該方法就呼叫一次

        * */

       YuLeQuan proxy = (YuLeQuan) Proxy.newProxyInstance(

              yl.getClass().getClassLoader(),

              yl.getClass().getInterfaces(),

              new InvocationHandler() {

                  //proxy:代理

                  //method:封裝了每一個遍歷的方法

                  //args:方法引數

                  //object  返回值

                  @Override

                  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                     System.out.println("開始");

                     //呼叫方法並返回

                     Object obj = method.invoke(yl, args);

                      System.out.println("結束");

                     return obj;

                  }

              });

      

       //3.呼叫代理物件方法

       proxy.play();

       proxy.kongfu();

 

  • Cglib的動態代理(目標類)
  • 匯入jar(cglib.jar,asm.jar)
//1.建立目標類物件

        Lyf lyf = new Lyf();

       

        //2.建立代理物件

        Enhancer enhancer = new Enhancer();

          //2.1 說明父子關係

          enhancer.setSuperclass(Lyf.class);

          //2.2 方法怎麼處理(回撥機制)  攔截每一個方法然後新增增強

          enhancer.setCallback(new MethodInterceptor() {

            @Override

            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

                System.out.println("開始");

                Object obj = method.invoke(lyf, args);

                System.out.println("結束");

                return obj;

            }

        });

        Lyf ly = (Lyf) enhancer.create();

       

        //3.呼叫方法

        ly.play();