zoukankan      html  css  js  c++  java
  • 17.Java 反射机制

    1.反射的定义

    反射之中包含了一个“反”的概念,所以要想解释反射就必须先从“正”开始解释,一般而言,当用户使用一个类的时候,应该先知道这个类,而后通过这个类产生实例化对象,但是“反”指的是通过对象找到类。                                                              

    2.Class对象

    2.1 概述

    Class对象是反射的起点,可以利用类的Class对象创建类的实例(newInstance),同时提供了操作类的工具,可以获取类的详细信息,并且使用特殊的技术实现类的加载(运行时加载,在编译的时候还没有该类的class文件)。

    2.2 Class对象的获取方式

    • a.使用类的字面常量
        • Class<Integer> c=Integer.class;     备注:编译时会进行检查,不需要捕获ClassNotFoundException,Class对象的类型也是明确的。
    • b.使用forName函数
        • Class<?> c=Class.forName("Integer");              备注:需要捕获异常,而且Class对象的类型是Class<?>,类型不明确,可以使用asSubClass进行转换,但是只能转换到Class<? extends Integer>。
        • Class<? extends Integer> u=c.asSubClass(Integer.class);
        • Class<? exnteds Integer> u1=c.getClass(new Integer(10).getClass());
    • c.使用getClass()函数
        • Integer integer=new Integer(10);
        • Class<? extends Integer> c=intger.getClass();   备注:使用对象实例获取Class对象。

    3.类型检查

    3.1概述

    Class对象提供了很多获取类信息的工具,可以获取类的方法,属性,进行类型判断,创建类的对象实例等等。

    3.2 相关API介绍

    • a.获取类的构造函数
    • public class Main {
          public static void main(String[] atgs) throws ClassNotFoundException {
              printTypeInfo("MyClass");
          }
         /**
         获取类的构造函数
      */ public static void printTypeInfo(String className){ try { Class<?> c = Class.forName(className); Constructor<?>[] constructors=c.getConstructors(); for(Constructor<?> constructor:constructors){ System.out.println(constructor); } }catch(ClassNotFoundException e){ e.printStackTrace(); } } } class MyClass { private int num=10; public MyClass(int num){ this.num=num; } public MyClass(){ } @Override public String toString(){ return String.format("%d",num); } } 
    • 备注:1.使用反射创建类的实例,Class.newInstance(),类中必须又一个无参数的构造函数,否则会报错。

    •          2.输出:public MyClass(int)

                       public MyClass()

    • 利用构造函数获取相关的对象
    • 用带参数构造函数,创建实例
    • Constructor<?> constructor=c.getConstructor(int.class);
      MyClass myClass=(MyClass)constructor.newInstance(5);
      System.out.println(myClass); 
    • 备注:1.上述的代码没有捕获异常,不能直接执行
    •          2.Class.newInstance()其实也就是获取类的无参构造函数,然后创建对象。
    • b.获取类的一般函数
    • public static void printTypeInfo(String className) {
          try {
               Class<?> c=Class.forName(className);
               for(Method method:c.getMethods()){
                  System.out.println(method);
               }
          } catch (ClassNotFoundException e) {
               e.printStackTrace();
          }
      } 
    • 备注:
    • 只能获取构造函数之外的函数,但是还包括从父类中继承来的函数
    • 获取特定的函数
    • getMethod(String methodName,Class<?> ...);
    • 例子:获取特定函数并执行Method.invoke(Obj,Class<?>...)---------动态执行Java的函数
    • public static void main(String[] args){
          Class<?> c=Class.forName(className);
          Method method=c.getMethod("getInfo",String.class);
          System.out.println(method.invoke(c.newInstance(),new String("123")));
      }
      
      class MyClass {
          private int num=10;
          public MyClass(int num){
              this.num=num;
          }
      
          public MyClass(){
          }
      
          public String getInfo(String string){
              return String.format("get : %s",string);
          }
      
          @Override
          public String toString(){
              return String.format("%d",num);
          }
      }
    • 备注:不能直接执行,没有捕获异常,为了看一来比较清楚
    • c.获取类的属性
    • public static void printTypeInfo(String className) {
              try {
                  Class<?> c=Class.forName(className);
                  Field[] fields=c.getDeclaredFields();
                  for(Field field:fields){
                      System.out.println(field);
                  }
      
              } catch (ClassNotFoundException e) {
                  e.printStackTrace();
              }
          }
    • 备注:还可以获取制定的属性 :field = c.getDeclaredField("num");
    • 操作类的属性,赋值-取值
    • 可能会有访问权限的问题,比如private的属性就不能进行操作,此时可以使用field.setAccessible(true)进行“破坏”面向对象的封装。
    • field.setAccessible(true);
      field.set(myClass,123);
      
    • d.备注
    • 反射还有很所用处,例如获取泛型的参数化类型,操作注解等等。

    4.代理

    • a.一般的代理设计模式
    • public class Main {
          public static void main(String[] atgs) {
              proxy proxy=new ProxyServer(new RealServer());
              proxy.doSomthing();
          }
      }
      
      interface proxy{
          void doSomthing();
      }
      
      class RealServer implements proxy{
          @Override
          public void doSomthing(){
              System.out.println("doSomething from RealServer");
          }
      }
      
      class ProxyServer implements proxy{
          private proxy realServer;
          public ProxyServer(proxy realServer){
              this.realServer=realServer;
          }
      
          @Override
          public void doSomthing(){
              realServer.doSomthing();
          }
      }
      
    • b.利用反射的动态代理设计模式
    • import java.lang.reflect.*;
      
      /**
       * Created by yangyun on 2016/11/30.
       */
      public class Main {
          public static void main(String[] atgs) {
              myProxy myProxyInterface=(myProxy) Proxy.newProxyInstance(
                      RealServer.class.getClassLoader(),
                      RealServer.class.getInterfaces(),
                      new ProxyHandler(new RealServer())
              );
              myProxyInterface.doSomthing();
          }
      }
      
      interface myProxy{
          void doSomthing();
      }
      
      class RealServer implements myProxy{
      
          public RealServer(){
          }
      
          @Override
          public void doSomthing(){
              System.out.println("from RealServer doSomething()");
          }
      }
      
      class ProxyHandler implements InvocationHandler{
          private Object realProxy;
          public ProxyHandler(Object realProxy){
              this.realProxy=realProxy;
          }
      
          @Override
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
              System.out.println("before invoke()");
              Object result=method.invoke(realProxy,args);
              System.out.println("after invoke()");
              return result;
          }
      }
      
    •  有什么意义?

    • 1.如果需要在调用代理服务器的函数之前或者之后做一些别的工作,可以不修改服务器端的代码,只需要修改InvocationHandler的invloke()函数就可以。
    • 2.动态代理还是AOP(Spring 面向切面编程的基础)
    • 3.静态代理每增加一个服务类就应该添加一个代理类,动态代理的话只需要一个InvokationHandler就可以了
    • 备注:
    • System.out.println(myProxyInterface.getClass().getName());//$Proxy0
    • 通过 Proxy.newProxyInstance 创建的代理对象是在jvm运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,也不是我们定义的那组接口的类型,而是在运行是动态生成的一个对象,并且命名方式都是这样的形式,以$开头,proxy为中,最后一个数字表示对象的标号
    • 我自己的理解可能会有错
    • proxy.newProxyInstance()产生的其实是代理对象,这个代理对象会实现被“代理类RealServer”的所有接口,这里我们把它转型为proxy接口。
    • 当我通过代理对象来调用方法的时候,起实际就是委托由其关联到的 handler 对象的invoke方法中来调用,并不是自己来真实调用,而是通过代理的方式来调用的,输出method可以看到其实就是doSomething函数。
    • 这就是我们的java动态代理机制,代理对象执行函数全部都通过InvokationHandler的invoke()函数。

    参考文献

    https://www.zhihu.com/question/24304289

    http://blog.csdn.net/xu__cg/article/details/52882023

    http://blog.csdn.net/liujiahan629629/articzle/details/18013523

    http://www.cnblogs.com/xiaoluo501395377/p/3383130.html

  • 相关阅读:
    Python动态展示遗传算法求解TSP旅行商问题
    MOEAD算法中均匀权向量的实现---Python
    HDU 5294 多校第一场1007题 最短路+最小割
    POJ 3261 Milk Patterns sa+二分
    HDU 4292 FOOD 2012 ACM/ICPC Asia Regional Chengdu Online
    CodeForces 201A Clear Symmetry
    POJ 1679 The Unique MST 确定MST是否唯一
    POJ 3268 Silver Cow Party 最短路 基础题
    POJ 2139 SIx Degrees of Cowvin Bacon 最短路 水題
    POJ2229 Sumsets 基礎DP
  • 原文地址:https://www.cnblogs.com/yangyunnb/p/6126109.html
Copyright © 2011-2022 走看看