【盘点Java框架常用技术】Java反射
2019-08-15 21:32
218 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/HoyingHan/article/details/99656570
【一】简介
- 允许运行时的Java程序获取自身信息,同时操作类或对象的内部属性,最通俗易懂的解释,就是让你根据一个String来得到你要的实体对象
- 功能:
-
运行时判断对象所属类
- 运行时构造类的对象
- 运行时判断类的属性和方法
- 运行时调用任意一个类的方法
下面是相关的四个类,包含了我们定义一个类所能用到的所有属性和方法。
- Class
- Field
- Method
- Constructor
【二】常用方法
-
获取Class对象
-
Class类中的静态方法forName
- 直接获取某一个对象的 class
- 调用某个对象的 getClass() 方法
-
反射获取类的属性
-
getFields():Field[] - 只能获取public的字段,包括父类的
- **getDeclaredFields():Field[] **- 只能获取自己声明的各种字段,包括public,protected,private
-
获取方法:
-
getMethod(String,Class<?>…):Method - 根据方法名和参数获取方法
- getDeclaredMethods():Method[]
-
invoke()
调用包装在当前Method对象中的方法
Method和NativeMethodAccessorImpl类中的invoke()方法:
public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { Class<?> caller = Reflection.getCallerClass(); checkAccess(caller, clazz, obj, modifiers); } } MethodAccessor ma = methodAccessor; if (ma == null) { ma = acquireMethodAccessor(); } return ma.invoke(obj, args); }
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); }
在上述方法中,有两点是比较重要的:
- 根据Class对象获取Method方法时,参数:方法名和参数的CLass类型
- 调用method.invoke(obj, args)
【三】原理探究
如果想要理解反射,就首先要对Java类加载的方式有了解。
我们知道,我们写的Java文件会被编译成.class文件(字节码文件),才能在JVM中执行,是通过类加载器进行加载,
java.lang.ClassLoader#loadClass(java.lang.String, boolean)是加载一个类的核心方法,
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class<?> c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { if (parent != null) { c = parent.loadClass(name, false); } else { c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); c = findClass(name); // this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { resolveClass(c); } return c; } }
主要逻辑分为3步
- 检查是否已加载,如果已加载则直接返回
- 遵循双亲委派模式,先调用父类加载器加载器
- 如果父类加载器加载失败,调用findClass加载
当我们打开findClass方法时,会不会有些诧异,直接抛了个异常,这是因为ClassLoader是一个抽象类,是无法通过new创建一个对象的,也就是说,你无法通过ClassLoader类直接加载.class文件,只能写一个子类继承ClassLoader,然后覆盖findClass方法,定义自己的加载逻辑。
protected Class<?> findClass(String name) throws ClassNotFoundException { throw new ClassNotFoundException(name); }
在自定义加载逻辑的时候,通常的做法是,读取一个字节数组byte[] b,然后调用ClassLoader的defineClass()方法,于是返回了一个Class对象
private native Class<?> defineClass0(String name, byte[] b, int off, int len, ProtectionDomain pd); private native Class<?> defineClass1(String name, byte[] b, int off, int len, ProtectionDomain pd, String source); private native Class<?> defineClass2(String name, java.nio.ByteBuffer b, int off, int len, ProtectionDomain pd, String source);
Class类的内部类 ReflectionData,里面的内容与xxx.class文件中的内容映射,作用就是缓存从JVM中读取类的如下属性数据。同时由于一个类中包含的内容信息量过大,所以被拆成了四个类,也就是上面提到的- Class、Field、Method、Constructor
private static class ReflectionData<T> { volatile Field[] declaredFields; volatile Field[] publicFields; volatile Method[] declaredMethods; volatile Method[] publicMethods; volatile Constructor<T>[] declaredConstructors; volatile Constructor<T>[] publicConstructors; // Intermediate results for getFields and getMethods volatile Field[] declaredPublicFields; volatile Method[] declaredPublicMethods; volatile Class<?>[] interfaces; // Value of classRedefinedCount when we created this ReflectionData instance final int redefinedCount; ReflectionData(int redefinedCount) { this.redefinedCount = redefinedCount; } }
相关文章推荐
- 汇总java生态圈常用技术框架、开源中间件,系统架构及经典案例等
- java反射技术常用操作
- Java 反射学习(四)反射技术开发框架原理简单实现
- Java基础加强之框架的概念及反射技术的开发框架的原理
- (Java基础--反射)框架的概念及用反射技术开发框架的原理
- 浅谈Java反射(Reflect)技术--常用方法
- Android框架常用java基础知识:反射,注解,动态代理
- Java 三大框架常用的技术_Spring部分
- javaWeb常用框架技术总结
- Java高新技术之框架的概念及用反射技术开发框架的原理和配置文件
- java常用的几个开源框架包
- 详细介绍java的反射技术
- java的反射技术功能十分强大,整理一些资料!!
- Java知识拾遗:三大框架的技术起源
- java反射:建立框架
- 深入浅出学习hibernate框架(三):java的反射机制
- JAVA 反射技术 万用分页标签 核心代码 (图)
- java的反射技术功能十分强大,整理一些资料!!
- 利用JAVA反射技术查找一个类的所有属性
- 涉及关于java的框架、技术、网站清单(转)