Java 的反射机制你了解多少?
不知道多少次听说过了Java反射机制的使用,比如:Spring 框架如何实例化IoC容器中的Bean,编码过程中如何动态的清理对象中的字段信息等等。工作中只是听说、看同事们编码实践,但是自己却只是概念上的认识,浅显粗略,今天就补一下反射的知识点,自己欠下的债,迟早是要还的。
一. 什么是反射?
在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象方法的功能就称为java语言的反射机制。通俗点讲,通过反射,该类对我们来说是完全透明的,想要获取任何东西都可以。
想要使用反射机制,就必须要先获取到该类的字节码文件对象(.class),通过字节码文件对象,就能够通过该类中的方法获取到我们想要的所有信息(方法,属性,类名,父类名,实现的所有接口等等),每一个类对应着一个字节码文件也就对应着一个Class类型的对象,也就是字节码文件对象。
获取类的字节码文件对象有三种方式:
Class clazz1 = Class.forName("全限定类名"); // 通过Class类中的静态方法forName,直接获取到一个类的字节码文件对象,此时该类还是源文件阶段,并没有变为字节码文件。
Class clazz2 = User.class; // 当类被加载成.class文件时,此时Person类变成了.class,在获取该字节码文件对象,也就是获取自己, 该类处于字节码阶段。
User user = new User();
Class clazz3 = p.getClass(); // 通过类的实例获取该类的字节码文件对象,该类处于创建对象阶段
有了字节码文件对象才能获得类中所有的信息,我们在使用反射获取信息时,也要考虑使用上面哪种方式获取字节码对象合理,视不同情况而定。下面介绍Class类的功能。
二. 反射机制能够动态获取类的哪些信息?
2.1 通过字节码对象创建实例对象
// 通过字节码对象创建实例对象
Class<?> userClz1 = Class.forName("com.base.reflect.entity.User");
User user1 = (User) userClz1.newInstance();
log.info("userClz1 instance = {}", user1);
Class<?> userClz2 = User.class;
User user2 = (User) userClz1.newInstance();
log.info("userClz1 instance = {}", user2);
2.2 获取指定构造器方法,constructor 有参无参创建实例
// 获取指定构造器,有参无参构造实例对象
Class<?> userClz3 = Class.forName("com.base.reflect.entity.User");
Constructor<?> constructor1 = userClz3.getConstructor();
User user3 = (User) constructor1.newInstance();
log.info("constructor1 user3 = {}", user3); Constructor<?> constructor2 = userClz3.getConstructor(String.class, String.class, String.class, Date.class, String.class, Date.class);
User user4 = (User) constructor2.newInstance("admin", "123456", "admin", new Date(), "admin", new Date());
log.info("constructor user4 = {}", constructor2);
总结上面创建实例对象:
a)Class类的 newInstance() 方法是使用该类无参的构造函数创建对象;
b)可以调用Class类的 getConstructor(Class<?>... parameterTypes) 方法获取一个指定参数的构造函数,然后再调用Constructor类的newInstance(value1, value2 ...)方法创建对象;
获取类中全部构造方法:
// 获取当前类中 public 类型的构造函数
Constructor<?>[] constructors = userClz3.getConstructors();
// 获取当前类中 public protected default private 类型的构造函数
Constructor<?>[] declaredConstructors = userClz3.getDeclaredConstructors();
2.3 获取指定的方法,动态调用方法
// 动态获取类中的方法
User user5 = new User("lisi", "123456", "lisi", new Date(), "lisi", new Date());
log.info("user5 = {}", user5);
// 获取User类中的 setParams 方法,并指定方法中的参数类型
Method method = user5.getClass().getMethod("setParams", String.class, String.class);
// 执行方法,传递参数【指明运行哪个对象中的哪个方法】
method.invoke(user5,"hello", "123123");
log.info("user5 = {}", user5);
输出结果:
user5 = User(username=lisi, password=123456, createBy=lisi, createTime=Thu Oct 22 17:21:52 CST 2020, updateBy=lisi, updateTime=Thu Oct 22 17:21:52 CST 2020) user5 = User(username=hello, password=123123, createBy=lisi, createTime=Thu Oct 22 17:21:52 CST 2020, updateBy=lisi, updateTime=Thu Oct 22 17:21:52 CST 2020)
总结上面动态调用类中的方法:
Class.getMethod(String, Class...) 和 Class.getDeclaredMethod(String, Class...) 方法可以获取类中的指定方法,如果为私有方法,则需要打开一个私有方法权限。
setAccessible(true);用 invoke(Object, Object...) 可以调用该方法;
获取类中全部方法:
// 获取当前类中 public 类型的方法
Method[] methods = User.class.getMethods();
// 获取当前类中 public protected default private 类型的方法
Method[] declaredMethods = User.class.getDeclaredMethods();
2.4 获取指定的字段,动态设置对象中字段的值
// 动态获取对象中的 Field
User user6 = new User("zhangsan", "123456", "zhangsan", new Date(), "zhangsan", new Date());
log.info("user6 = {}", user1);
clearFields(user6, "createBy", "createTime", "updateBy", "updateTime");
log.info("user6 = {}", user6);
// 清理对象中的字段信息
private static void clearFields(User user1, String... params) throws IllegalAccessException, NoSuchFieldException {
for (String param : params) {
Field field = user1.getClass().getDeclaredField(param);
field.setAccessible(true);
Object obj = field.get(user1);
log.info("obj = {}", obj);
field.set(user1, null);
}
}
输出结果:
user6 = User(username=zhangsan, password=123456, createBy=zhangsan, createTime=Thu Oct 22 17:33:18 CST 2020, updateBy=zhangsan, updateTime=Thu Oct 22 17:33:18 CST 2020)
obj = zhangsan
obj = Thu Oct 22 17:33:18 CST 2020
obj = zhangsan
user6 = User(username=zhangsan, password=123456, createBy=null, createTime=null, updateBy=null, updateTime=null)
获取类中全部字段信息:
// 获取当前类中 public 类型的字段
Field[] fields = User.class.getFields(); // 获取当前类中 public protected default private 类型的字段
Field[] fields = User.class.getDeclaredFields();
使用场景:在使用 MyBatis 拦截器 Interceptor 对应用添加、更新对象时,需要重新设置 createBy createTime updateBy updateTime 字段信息,动态的清理一些字段信息,然后重新设置。
Java 的反射机制你了解多少?的更多相关文章
- Java 类反射机制分析
Java 类反射机制分析 一.反射的概念及在Java中的类反射 反射主要是指程序可以访问.检测和修改它本身状态或行为的一种能力.在计算机科学领域,反射是一类应用,它们能够自描述和自控制.这类应用通过某 ...
- java的反射机制
一.java的反射机制浅谈 最近研究java研究得很给力,主要以看博文为学习方式.以下是我对java的反射机制所产生的一些感悟,希望各位童鞋看到失误之处不吝指出.受到各位指教之处,如若让小生好好感动, ...
- Java中反射机制和Class.forName、实例对象.class(属性)、实例对象getClass()的区别
一.Java的反射机制 每个Java程序执行前都必须经过编译.加载.连接.和初始化这几个阶段,后三个阶段如下图: 其中
- java笔记--反射机制之基础总结与详解
一.反射之实例化Class类的5种方式: java的数据类型可以分为两类,即引用类型和原始类型(即基本数据类型). 对于每种类型的对象,java虚拟机会实例化不可变的java.lang.Class对象 ...
- JAVA的反射机制学习笔记(二)
上次写JAVA的反射机制学习笔记(一)的时候,还是7月22号,这些天就瞎忙活了.自己的步伐全然被打乱了~不能继续被动下去.得又一次找到自己的节奏. 4.获取类的Constructor 通过反射机制得到 ...
- java笔录---反射机制(1)
引言 为了方便记忆java的反射机制,在这里仔细的总结了一下.主要是怕以后忘记了,这样也方便回忆.因为最近利用空余时间深入的了解spring和Mybatis框架, 像spring中核心模块IO ...
- Java高新技术 反射机制
Java高新技术 反射机制 知识概要: (1)反射的基石 (2)反射 (3)Constructor类 (4)Field类 (5)Method类 (6)用反射方 ...
- java的反射机制浅谈(转)
原文链接:java的反射机制浅谈 一.java的反射机制浅谈 1.何谓反射机制 根据网文,java中的反射机制可以如此定义: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性 ...
- 【转】Java利用反射机制访问私有化构造器
Java利用反射机制访问私有化构造器 博客分类: java 我们都知道,当一个类的构造方法被设为私有的时候(private),在其他类中是无法用new来实例化一个对象的. 但是有一种方法可以把带有 ...
- 【转】java原理—反射机制
一.什么是反射:反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力.这一概念的提出很快引发了计算机科学领域关于应用反射性的研究.它首先被程序语言 ...
随机推荐
- kinaba 安装踩坑: FATAL Error: [elasticsearch.url]: definition for this key is missing 转
安装 https://www.jianshu.com/p/875457cb8da6 操作系统:Linux kibana 版本: 7.4.0 1. 在/etc/yum.repos.d/ 下新建 ...
- spring boot: 设计接口站api的版本号,支持次版本号(spring boot 2.3.2)
一,为什么接口站的api要使用版本号? 1,当服务端接口的功能发生改进后, 客户端如果不更新版本, 则服务端返回的功能可能不能使用, 所以在服务端功能升级后, 客户端也要相应的使用 ...
- Nexus 安装教程
Nexus 安装教程 一. CentOS设置 1. 更换阿里源 curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/ ...
- SQL报表语句;SQL获取今日、本周、本月数据
SQL报表语句 SQL获取今日.本周.本月数据 本日:select * from table where datediff(dd,C_CALLTIME,getdate())=0 --C ...
- 【机器学习 Azure Machine Learning】使用VS Code登录到Linux VM上 (Remote-SSH), 及可直接通过VS Code编辑VM中的文件
问题描述 在平常的工作习惯中,如果使用VS Code做脚本的开发,是一个非常好用的工具,现在也可以通过VS Code的不同方式来连接到Linux VM中(ssh), 第一种是VS Code的Termi ...
- 普通人如何站在时代风口学好AI?这是我看过最好的答案
摘要:当前,数据.算法.算力的发展突破正推动AI应用的逐步落地. AI是什么? 根据维基百科的定义,人工智能是一种新的通用目的技术(GPT, General Purpose Technology),它 ...
- 在电脑上操作手机屏幕scrcpy工具就搞定了
手机安卓版本:10 电脑:win64 使用步骤 电脑步骤 下载scrcpy scrcpy 是免费开源的投屏软件,支持将安卓手机屏幕投放在 Windows.macOS.GNU/Linux 上,并可直接借 ...
- Nginx02---配置文件
Nginx(二)------nginx.conf 配置文件 目录 1.nginx.conf 的主体结构 2.全局块 3.events 块 4.http 块 ①.http 全局块 ②.server ...
- 从一个例子入手Istio
转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com 本文使用的Istio源码是 release 1.5. 本篇是Istio系列的第一篇,希望 ...
- Paraview教程
快速入门 https://www.youtube.com/watch?time_continue=1017&v=Y1RATo2swM8 Cyprien Rusu系列 Paraview Vide ...