Java反射知识总结

在不少状况下,咱们知道如何编写反射相关类或者方法,可是没法口述反射是什么,里面的机制是什么,下面我先如浅入深介绍反射。设计模式

一、定义

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

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

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

// 普通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进行实例化,这就须要在动态运行时才须要建立一个实例。框架

二、用法

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)
复制代码

**三、**invoke

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

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);
复制代码

四、总结

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

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

缺点:ui

  • 性能消耗大,慢于直接使用类、方法、属性等性能
  • 增长逻辑难度,会带来维护困难
相关文章
相关标签/搜索