Java反射知识总结

在很多情况下,我们知道如何编写反射相关类或者方法,但是无法口述反射是什么,里面的机制是什么,下面我先如浅入深介绍反射。

1、定义

反射 (Reflection) 是 Java 的特征之一,它允许运行中动态加载Java 程序获取自身的信息,并且可以操作类或对象的内部属性,是一种功能强大且复杂的机制,可以用在下面四个方面:

  • 在运行时分析类的能力
  • 在运行时查看对象
  • 实现通用的数组操作代码
  • 利用Method对象

上面是正式的反射定义,比较抽象,用个大白话来说,反射就是动态加载类、调用方法和访问属性,它不需要事先知道运行对象是谁。反射的重点在运行时而不是编译时,也就是动态加载。下面我们先来看下一个简单的例子

// 普通new
User user = new User();
user.setEmail("xxxx@xxx.com");

// 反射例子
try {
    Class clz = Class.forName("com.fomin.demo.model.User");
    Method method = clz.getMethod("setEmail", String.class);
    Constructor constructor = clz.getConstructor();
    Object object = constructor.newInstance();
    method.invoke(object, "aaa@xx.com");
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException
        | InstantiationException | InvocationTargetException e) {
    e.printStackTrace();
}

上面需要一个User实例,正常情况下,我们只需要new一个实例就行,但我们也会遇到一些特殊情况,我不知道初始化的类对象是什么,无法使用new进行实例化,这就需要在动态运行时才需要创建一个实例。

2、用法

   Java的反射机制的实现要借助于4个类:Class,Constructor,Field,Method,并且如果需要创建实例,可以使用newInstance创建,例如,clz.newInstance或者constructor.newInstance
  • Class:代表的是类对象,反射的核心。在反射中,首先需要获取到该类的Class对象。有三种实现方式
//使用 Class.forName 静态方法
Class clz = Class.forName("com.fomin.demo.model.User");

//使用 .class 方法
Class clz = User.class;

//使用类对象的 getClass() 方法
User user = new User();
Class clz = user.getClass();
  • Constructor:类的构造器对象,用来获取构造函数方法,使用方式有以下几种:
//获取指定参数获得public构造函数
Constructor<T> getConstructor(Class<?>... parameterTypes);

//根据指定参数获取public和非public的构造函数
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes);
  • Field:类的属性对象
//获取类的所有声明字段,但不能得到其父类的成员变量,包含私有的
Field[] getDeclaredFields()

//获取指定参数的类的所有声明字段,但不能得到其父类的成员变量,包含私有的
Field getDeclaredField(String name)

//获取类的所有公有声明字段,但不能得到其父类的成员变量
Field[] getFields()

//获取指定参数的类的所有公有声明字段,但不能得到其父类的成员变量
Field getField(String name)
  • Method:类的方法对象
//获取类的所有公用(public)方法,包括其继承类的公用方法
Method[] getMethods()

//获取特定的公用(public)方法,第一个参数为方法名称,后面的参数为方法的参数对应Class的对象
Method getMethod(String name, Class<?>... parameterTypes)

//获取类或接口声明的所有方法,包括公共、保护、默认访问和私有方法,不包括继承方法
Method[] getDeclaredMethods()

//获取特定的方法,第一个参数为方法名称,后面的参数为方法的参数对应Class的对象
Method getDeclaredMethod(String name, Class<?>... parameterTypes)

**3、**invoke

属于Method的一个方法,用来反射执行方法的,包含两个参数,一个是Object obj表示被调用方法底层所属对象,Object… args表示调用方法是传递的实际参数。
invoke中核心在MethodAccessorImpl,NativeMethodAccessorImpl,DelegatingMethodAccessorImpl这三个类中,其中NativeMethodAccessorImpl和DelegatingMethodAccessorImpl继承了抽象类MethodAccessorImpl。并且 NativeMethodAccessorImpl 对象交给 DelegatingMethodAccessorImpl 对象代理。
在执行invoke时,首先需要对非重写方法检查权限,对非public方法,进行二次检查checkAccess。

if (!override) {
    if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
        Class<?> caller = Reflection.getCallerClass();
        checkAccess(caller, clazz, obj, modifiers);
    }
}

获取当前的MethodAccessor,如果是空的,调用acquireMethodAccessor创建,首先先从root获取,还是为空调用ReflectionFactory.newMethodAccessor创建一个,并设置在root中。

MethodAccessor tmp = null;
if (root != null) tmp = root.getMethodAccessor();
if (tmp != null) {
    methodAccessor = tmp;
} else {
    // Otherwise fabricate one and propagate it up to the root
    tmp = reflectionFactory.newMethodAccessor(this);
    setMethodAccessor(tmp);
}

最后调用NativeMethodAccessorImpl中的native方法invoke0

public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
    if (++this.numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(this.method.getDeclaringClass())) {
        MethodAccessorImpl var3 = (MethodAccessorImpl)(new MethodAccessorGenerator()).generateMethod(this.method.getDeclaringClass(), this.method.getName(), this.method.getParameterTypes(), this.method.getReturnType(), this.method.getExceptionTypes(), this.method.getModifiers());
        this.parent.setDelegate(var3);
    }

    return invoke0(this.method, var1, var2);
}

void setParent(DelegatingMethodAccessorImpl var1) {
    this.parent = var1;
}

private static native Object invoke0(Method var0, Object var1, Object[] var2);

4、总结

反射使用的地方很多,例如AOP思想就是需要用到发射、模块化的开发,通过反射去调用对应的字节码;动态代理设计模式也采用了反射机制, Spring/Hibernate 等框架。
优点

  • 无需知道对象是什么,可以使用其内部相关的方法、属性等
  • 提高代码的灵活度,可用于通用模块开发
  • 提高扩展性,降低耦合性,提高自适应能力

缺点:

  • 性能消耗大,慢于直接使用类、方法、属性等性能
  • 增加逻辑难度,会带来维护困难
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值