目录一、反射1、class类2、访问字段3、调用方法4、调用构造方法5、获取继承对象6、动态代理二、sping中的反射

本篇转自:本篇内容spring中的反射

java中的反射(一):
java中的反射(二):

一、Spring中的反射

、创建 Bean 实例时的反射

// 通过类加载器,根据 class 路径,得到其类对象
Class<?> clz = ().getContextClassLoader().loadClass("");
// 根据类对象生成 Bean 实例
return ();

反射体现在 (); 中,核心代码可分为两部分:

1、利用反射获取当前类 PetStoreService 的所有构造方法信息(Constructor 对象)

// java.lang.Class.java
// 调用 native 方法,此时 publicOnly 为 false
res = getDeclaredConstructors0(publicOnly);
// native 方法,从 jvm 中的 class 文件中获取构造方法信息,再转换为 Constructor 对象
private native Constructor<T>[] getDeclaredConstructors0(boolean publicOnly);

2、利用反射通过默认构造方法生成实例

// sun.reflect.NativeConstructorAccessorImpl.java
// 调用 native 方法,var1 代表构造方法的参数,此时为 null
return newInstance0(this.c, var1);
// native 方法,真正生成实例的方法,执行 class 文件的构造方法 <init>
private static native Object newInstance0(Constructor<?> var0, Object[] var1);

、构造方法依赖注入时的反射

// 通过反射获取当前类所有的构造方法信息(Constructor 对象)
Constructor<?>[] candidates = ();
// 设置构造方法参数实例
Object[] argsToUse = new Object[];
argsToUse[i] = getBean((i));
// 使用带有参数的 Constructor 对象实现实例化 Bean。此时使用反射跟上面一样(newInstance0),只是多了参数
return constructorToUse.newInstance(argsToUse);

、setter() 方法依赖注入时的反射

// 通过反射获取当前类所有的方法信息(Method 对象)
Method[] methods = ().getDeclaredMethods();
// 获得方法参数实例
Object propertyBean = getBean(propertyName);
// 通过反射执行调用 setter() 方法。invoke:调用方法,propertyBean 作为方法的参数
(bean, propertyBean);

().getDeclaredMethods(); 中的核心代码:

// java.lang.Class.java
// 调用 native 方法,publicOnly 为 false
getDeclaredMethods0(publicOnly);
// native 方法,从 jvm 中的 class 文件中获取方法信息,再转换为 Method
private native Method[]      getDeclaredMethods0(boolean publicOnly);

(bean, propertyBean); 中的核心代码:

// sun.reflect.NativeMethodAccessorImpl.java
// 调用 native 方法,var1: bean、var2: propertyBean
return invoke0(this.method, var1, var2);
// native 方法,运行 class 文件中的字节码指令
private static native Object invoke0(Method var0, Object var1, Object[] var2);

、@Autowired 依赖注入时的反射

// 通过反射得到当前类所有的字段信息(Field 对象)
Field[] fields = ().getDeclaredFields();
// 判断字段是否有 @Autowired 注解
Annotation ann = ();
// 设置字段可连接,相当于将非 public(private、default、protect)更改为 public
Accessible(true);
// 通过反射设置字段的值
(bean, getBean(()));

().getDeclaredFields(); 中的核心代码:

// java.lang.Class.java
// 调用 native 方法,此时 publicOnly 为 false
getDeclaredFields0(publicOnly);
// native 方法,从 jvm 中获取 class 文件的字段信息,再转换为 Field
private native Field[]       getDeclaredFields0(boolean publicOnly);

(bean, getBean(())); 中的核心代码:

// sun.reflect.UnsafeObjectFieldAccessorImpl.java
// 调用 native 方法,将目标对象 var1 指定偏移量 fieldOffset 处的字段值设置(修改)为 var2。var1 为 bean, var2 为参数实例
(var1, , var2);// sun.misc.Unsafe.java
// native 方法,直接修改堆中对象字段的数据
public native void putObject(Object var1, long var2, Object var4);

二、class 文件与类对象

class 文件由 java 文件编译而来,class 文件包含字段表、方法表、 方法(构造方法)等。

当类加载器将 class 文件加载进虚拟机元空间(Meta-space,jdk 1.8)时,虚拟机在元空间中创建一个与之对应的类对象(Class 实例)。并将 class 文件由存放在磁盘的静态结构转换为存放在内存的运行时结构。

我们可以认为一个类(class 文件)对应一个类对象,当前类的所有对象共用一个类对象。类对象作为访问存放在 jvm 的 class 文件的入口。

package java.lang;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;public final class Class<T> {private native Field[]       getDeclaredFields0(boolean publicOnly);private native Method[]      getDeclaredMethods0(boolean publicOnly);private native Constructor<T>[] getDeclaredConstructors0(boolean publicOnly);// ReflectionData 缓存反射对象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;...}
}

、获得类对象的方式

// 1、通过对象
Class cls = ();
// Object.java
public final native Class<?> getClass();// 2、通过类加载器
Class cls = ().getContextClassLoader().loadClass("");// 3、通过 Class 类,本质上也是通过类加载器
Class cls = ("");
// Class.java
private static native Class<?> forName0(String name, boolean initialize,ClassLoader loader,Class<?> caller)

三、反射方法

以下是常用的反射方法。

、Feild 相关

Field[] fields = (); // 获取所有公共的 Field(包括父类)
Field[] fields = (); // 获取当前类的所有 Field(不包括父类),包括公共和非公共
Field field = ("fieldName"); // 指定获取当前类某个 Field
(Object, Object); // 设置(修改)字段值
(Object); // 获取字段值

(Object) 核心代码:

// 调用 native 方法,获取字段对应的值
return unsafe.getObject(var1, );// native 方法,从堆中获取对象指定位置的对象
public native Object getObject(Object var1, long var2);

、Method 相关

Method[] methods = (); // 获取所有公共的 Method(包括父类)
Method[] methods = (); // 获取当前类的所有 Method(不包括父类),包括公共和非公共
(Object instance, Object... parameters); // 运行方法

运行方法使用场景:要么是修改对象的数据,如 void setter() 方法;要么是获得执行方法的返回结果。

String result = ().toString();

、Constructor 相关

Constructor<?>[] constructors = (); // 获取所有公共的 Constructor(包括父类)
Constructor<?>[] constructors = (); // 获取当前类的所有Constructor(不包括父类),包括公共和非公共
(Object... parameters); // 运行构造方法

当没有明确编写构造方法,Java 编译器将为该类构建一个默认构造函数

四、native 方法

Java 新增「Java 本地接口」(Java Native Interface,JNI),JNI 是一种包容极广的编程接口,允许我们从 Java 应用程序里调用 native 方法,native 方法由其它语言(C 、C++ 或汇编语言等)编写。native 方法用于实现 Java 无法处理的功能。

、简单示例

一个在 Java 中使用 Java 本地接口(JNI)的简单示例。

// Main.java
public class Main {public native int intMethod(int i);static {// 启动时载入 System.loadLibrary("Main");}public static void main(String[] args) {(new Main().intMethod(2));}
}
// :
// 将  引入
#include ""// 相当于继承 "" 的 Java_Main_intMethod
JNIEXPORT jint JNICALL Java_Main_intMethod(JNIEnv *env, jobject obj, jint i)
{return i * i;
}

编译与运行:

// 同时生成  和
javac Main.java -h .
// 根据  生成
gcc -dynamiclib -O3 \-I/usr/include \-I$JAVA_HOME/include \-I$JAVA_HOME/include/darwin \-o
// 指定 library 的路径为当前路径
java -cp . -Djava.library.path=$(pwd) Main

输出

4
/*  .h 作为头文件*/
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Main */#ifndef _Included_Main
#define _Included_Main
#ifdef __cplusplus
extern "C" {
#endif
/** Class:     Main* Method:    intMethod* Signature: (I)I*/
JNIEXPORT jint JNICALL Java_Main_intMethod(JNIEnv *, jobject, jint);#ifdef __cplusplus
}
#endif
#endif
javac Main.java -h .
// 可拆分为两个命令
javac Main.java
javah -jni Main

4.2、原理

运行 时,将 载入虚拟机,JVM 调用 的 Java_Main_intMethod,传入参数, 由系统直接运行,返回结果。

*env 用于将 java 类型数据与本地(此处为 C 语言)类型数据之间的转换
jint 还是 Java 数据类型,Java 基本数据类型可以映射(使用),不用通过 *env 转换

/*C code*/
JNIEXPORT void JNICALL Java_ClassName_MethodName(JNIEnv *env, jobject obj, jstring javaString)
{/*Get the native string from javaString*/const char *nativeString = (*env)->GetStringUTFChars(env, javaString, 0);/*Do something with the nativeString*//*DON'T FORGET THIS LINE!!!*/(*env)->ReleaseStringUTFChars(env, javaString, nativeString);
}

总结

反射反射,哪里体现反射字面意思?

可以这么理解,通过 native 方法得到反射对象,操作反射对象,像镜子一样,将反射到原对象上。

我们发现,反射和 native 方法的关系:

获取字段、方法、构造方法对象,native() 方法实现
获取字段值、设置修改字段值,native() 方法实现
运行方法,native() 方法实现
运行构造方法,native() 方法实现
我们可以得出结论,反射由 native 方法实现。

我们说通过反射实现一个功能,我们也可以说:

  1. 通过反射方法实现
  2. 通过反射 API 实现
  3. 通过 native 方法实现
    反射是一种非常规(native 方法实现)方式获取 class 文件信息、运行 class 文件字节码指令和操作对象数据的能力。

一句话总结 :反射是一种运行时获取和修改对象数据的能力。

关于运行时:Java 是静态语言,先编译,后运行。编译时不执行代码,代码都是运行时执行。

java 获取当前年_java中的反射(三) - kelexin相关推荐

  1. java 获取当前年_Java获取当前时间的年月日方法

    下面是编程之家 jb51.cc 通过网络收集整理的代码片段. 编程之家小编现在分享给大家,也给大家做个参考. package com.ob; import java.text.ParseExcepti ...

  2. java获取response数据_Java中实现Http请求并获取响应数据

    前言 在演示的功能代码中使用的请求http地址为:http://timor.tech/api/holiday/year/ 接口说明:获取指定年份或年月份的所有节假日信息.默认返回当前年份的所有信息. ...

  3. java 获取mysql链接_Java中如何获取mysql连接的3种方法总结

    前言 本文主要来说说三种 Java 中获取 mysql 连接的方式,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍: 第一种:传统的连接方式: 第二种:读取配置文件方式: 第三种:数据库 ...

  4. java获取子路径_Java中路径的获取

    1.Java中获取路径的方法:  Class_Name.class .getResource("")        //   Class_Name.class .getResour ...

  5. java 获取键盘输入法_Java中接收键盘输入的三种方法

    import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import ...

  6. java 获取线程某个_Java中如何唤醒“指定的“某个线程

    熟悉线程操作的小朋友应该知道,Java中线程的挂起和唤醒一般用synchronized + wait + notify完成. 比如: synchronized(o) { o.wait(); //wai ...

  7. java 获取剪切板_Java中有关剪切板的操作

    本地剪贴板只在当前虚拟机中有效.Java允许多个本地剪贴板同时存在,可以方便地通过剪贴板的名称来进行存取访问. 系统剪贴板与同等操作系统直接关连,允许应用程序与运行在该操作系统下的其它程序之间进行信息 ...

  8. java 获取int长度_Java中获取基本数据类型的长度

    Java中存在多个基本数据类型,如:int.float.double.short等.在实际应用中,我们有可能需要获取这些类型的字节数,获取数据类型的字节数可以通过直接写的方式,因为java中基本数据类 ...

  9. java invoke 方法说明_java中的反射,invoke方法

    invoke,就是通过函数名反射调用相应的函数.以下代码简单地介绍了java反射中invoke方法 package org.curry.tool; import java.lang.reflect.M ...

最新文章

  1. 【Mac】解决「无法将 chromedriver 移动到 /usr/bin 目录下」问题
  2. RDKit | 基于RDKit绘制黑白颜色的分子
  3. 浅谈双人游戏的设计与魅力——由《双人成行》引发的思考
  4. github 分支管理
  5. 计算机专业PS模版,计算机专业PS范例十一
  6. [深度学习] 一篇文章理解 word2vec
  7. web开发发送短信实现最简单的接口
  8. vuejs npm chromedriver 报错
  9. java开发的主流_盘点2019年Java开发中7项主流、热门的IT技术!
  10. 【Selenium-WebDriver自学】出现的问题和解决方案(十七)
  11. 给定一列非负整数,求这些数连接起来能组成的最大的数。
  12. Java 算法SM2加密解密
  13. python精确有理数实验_有理数类实验报告
  14. 干货分享 | B站SLO由失败转成功,B站SRE做对了什么?
  15. 华科_图形学笔记_05_初探造型技术_02
  16. js知识点 掘金_掘金js
  17. 分享三个前端学习方法和十项前端面试笔记:为想去的公司努力一把
  18. RedHat终端中文乱码解决,netterm经常变换颜色的解决
  19. Python-Opencv实现魔方边缘识别
  20. 通过免费采集软件做网站方法

热门文章

  1. java自定义sql查询条件_mybatis-plus QueryWrapper自定义查询条件的实现
  2. runnerw.exe: CreateProcess failed with error 193: %1 问题定位-idea
  3. MVC中使用T4模板
  4. response.sendRedirect(url)与request.getRequestDispatcher(url).forward(request,response)的区别
  5. UIScreen(屏幕)、UIWindow(画框)、UIView(画布)、didFinishLaunchingWithOptions的概念...
  6. Nokia5230连接电脑无线上网
  7. SQL格式化流水号位数
  8. 学生信息表 -通过选择年级和班级得到详细的学生信息名单
  9. Ubuntu18.04安装BeyondCompare
  10. WSL1安装GUI界面