Java reflection(反射)

1) 介绍

JAVA反射机制是在虚拟机运行状态中:

  • 对于任意一个类,都能够知道这个类的所有属性和方法;

  • 对于任意一个对象,都能够调用它的任意一个方法和属性;

这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

反射缺点

反射功能虽然强大,但不能随便使用,在能不用的情况下尽量不要使用,使用反射应该考虑以下问题:

  1. 性能开销 反射操作比非反射要慢,由于涉及动态解析,某些操作虚拟机是不优化的,应该尽量避免在频繁调用的代码中使用

  2. 安全       执行反射需要权限,在安全管理器下运行时可能不存在该权限。对于必须在受限安全上下文(例如 Applet)中运行的代码

  3. 封装暴露

    • 反射十分强大,可以访问私有(private)字段和方法,这用可能会导致代码功能失效并且破坏可移植性与封装性

    • 反射打破了抽象,因此可能会随着平台的升级而改变行为。

教程文档:https://docs.oracle.com/javase/tutorial/reflect/index.html

使用文档:Core Java Reflection

2) Classes

Class对象是所有反射API的入口,不可以自己创建,每个类或该类的实例对象,虚拟机都会实例化一个不可变的Class对象,该对象提供在运行时获取类的信息(属性名,方法名)的一组方法,通过类的对象实例可以访问属性数据,执行该类的对象方法,还有很多方法,如创建新的类和对象能力。

获取Class对象方式:

Class a = 类名.class
Class b = 对象.getClass();
Class c = 数组.getClass();
Class d = Class.forName("org.lls.User");

Class API

  • 字段

    • class.getFields()                  获取所有公有的字段

    • class.getDecalreFields()      获取所有的字段(包括私有、受保护、默认的)

    • class.getField(param)          获取公有字段

    • Field.set(Obje,value);           反射设置一个对象属性值

    • Field   该类提供对字段一系列操作

      • setAccessible()  访问检查,true表示禁止访问检查,false表示限制执行访问检查

  • 方法

    • class.getConstructors()                                  获取所有公有构造方法

    • class.getDeclaredConstructors()                    获取所有构造方法(包括:私有、受保护、默认、公有)

    • class.getConstructor(param)                         获取公有、无参的构造方法

    • class.getDeclaredConstructor(param)           获取私有构造方法

    • newInstance();                                               反射执行一个对象方法

    • setAccessible(boolean)                                 暴力访问(忽略掉访问修饰符),true打开权限,false关闭权限

    • Constructor  该类提供对方法与构造函数一系列操作

      • setAccessible()                                     访问检查,true表示禁止访问检查,false表示限制执行访问检查

  • 注解

    • getAnnotation()      用于获取(对象的注解,方法注解,字段注解)

    • Annotation  该类提供注解一系列操作

实例

/***

   *  1、获取属性上的指定类型的注释

   *  2、获取属性上的指定类型的注释的指定方法

   *  3、获取属性上的所有注释

   *  4、获取类上的所有注释

   *  5、获取方法上的所有注释

    * @author 2014-11-10 下午02:18:24

    * @param args

   */

  @SuppressWarnings("rawtypes")

  public static void main(String[] args) {


    Field[] fields =  User.class.getDeclaredFields();


    for(Field f : fields){

      String filedName = f.getName();
      System.out.println("属性名称:【"+filedName+"】");

      //1、获取属性上的指定类型的注释
      Annotation annotation = f.getAnnotation(XmlElement.class);

      
      //有该类型的注释存在
      if (annotation!=null) {

        //强制转化为相应的注释    
        XmlElement xmlElement = (XmlElement)annotation;

        //3、获取属性上的指定类型的注释的指定方法
        //具体是不是默认值可以去查看源代码
        if (xmlElement.name().equals("##default")) {

          System.out.println("属性【"+filedName+"】注释使用的name是默认值: "+xmlElement.name());
        }else {
          System.out.println("属性【"+filedName+"】注释使用的name是自定义的值: "+xmlElement.name());
        }

      }

      //2、获取属性上的所有注释
      Annotation[] allAnnotations = f.getAnnotations();

      for(Annotation an : allAnnotations){
        Class annotationType = an.annotationType();
        System.out.println("属性【"+filedName+"】的注释类型有: " + annotationType);
      }
      System.out.println("----------华丽的分割线--------------");

    }

    

    //4、获取类上的所有注释
    Annotation[] classAnnotation = User.class.getAnnotations();

    for(Annotation cAnnotation : classAnnotation){

      Class annotationType =  cAnnotation.annotationType();
      System.out.println("User类上的注释有: " +annotationType);

    }

    

    System.out.println("----------华丽的分割线--------------");

    // 5、获取方法上的所有注释
    Method method;
    try {

      method = User.class.getMethod("setPwd",String.class);

      Annotation[] methodAnnotations = method.getAnnotations();

      for(Annotation me : methodAnnotations){

        Class annotationType =  me.annotationType();

        System.out.println("setPwd方法上的注释有: " + annotationType);

      }

    } catch (SecurityException e) {

      e.printStackTrace();

    } catch (NoSuchMethodException e) {

      e.printStackTrace();

    }

  }

  @XmlElement
  public void setPwd(String pwd) {
    this.pwd = pwd;

  }

  public String getPwd() {
    return pwd;

  }

}

3) 动态代理

利用反射机制在运行时创建代理对象,JDK提供了java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy类,这两个类相互配合,入口是Proxy

Proxy主要静态方法

  • Proxy.getProxyClass(classLoader,class..)      获取代理类

  • Proxy.newProxyInstance(classLoader,class[],InvocationHandler)   创建代理对象

    1. 代理类的类加载器

    2. 要被代理的接口,只能是接口

    3. InvocationHandler代理的处理类,执行代理对象时,调用invoke进行代理拦截

  • Proxy.getInvocationHandler(Object proxy)     根据代理对象获取代理处理类

  • Proxy.isProxyClass(class)                                  判断是否代理类

代理实例

public class DebugProxy implements InvocationHandler {

    private Object obj;

    public static <T> T newInstance(T obj) {
        return (T) java.lang.reflect.Proxy.newProxyInstance(

                obj.getClass().getClassLoader(),

                obj.getClass().getInterfaces(),

                new DebugProxy(obj)
        );
    }



    private DebugProxy(Object obj) {
        this.obj = obj;
    }



    @Override
    public Object invoke(Object proxy, Method m, Object[] args)throws Throwable
    {
        Object result;
        try {
            System.out.println("前方法 " + m.getName());
            result = m.invoke(obj, args);
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        } catch (Exception e) {
            throw new RuntimeException("意外调用异常: " +e.getMessage());
        } finally {
            System.out.println("后方法 " + m.getName());
        }

        return result;
    }
}



@Test
public void t2(){

    Foo foo = DebugProxy.newInstance(new FooImpl());
    System.out.println(foo.say("你好"));

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值