一文带你了解Java反射机制
想要获取更多文章可以访问我的博客 - 代码无止境。
上周上班的时候解决一个需求,需要将一批数据导出到Excel。本来公司的中间件组已经封装好了使用POI生成Excel的工具方法,但是无奈产品的需求里面有个合并单元格的要求,工具类中找了半天也没发现适用的方法,就只能自己撸起袖子干了。导出Excel的工具方法会少不了使用反射,但是反射这东西对于我这种写业务代码的人来说接触比较少,所以就恶补了一下,写下这篇文章记录一下。
什么是反射
万物究其根,研究一样新东西,首先我们需要了解它是什么,干什么用的。在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。那么我们又能利用反射做什么呢?
- 在运行时分析类。
 - 在运行时查看对象,我们还可以利用反射编写一个toString方法供所有类使用。
 - 利用Method对象,在运行时任意调用一个对象的方法。
 
那么本篇文章将围绕者上面三个点来了解一下Java的反射机制。在开始之前,我们先来介绍一下一个类,这个类是我们在使用反射的过程中必不可少会使用到的一个类。
Class类
在运行时,Java运行时系统会为每一个对象都维护一个标识这个对象类型的信息,而保存这些信息的类型就是Class类。我们可以通过对象的getClass()方法来获取该对象对于的Class对象,就像下面这样。
User user = new User();
Class c = user.getClass();
这个世界上的任何东西都有它存在的意义,那么我们可以用Class对象来干什么呢?我们最常使用Class来判断一个对象是不是属于某个类型,就像下面这样:
User user = new User();
if (user.getClass() == User.class) {
    System.out.println("user is User");
}
当然我们也经常会使用Class类的getName()方法来获取某个类的名称。有写时候,我们还会利用它的newInstance()方法来获取某个类型的实例(当这类没有提供共有的构造方法时)。
利用反射分析类
分析一个类,无外乎就是查看这个类中的属性、方法以及其构造方法了。在Java的反射包中提供了三个类Field、Method以及Constructor来分别描述属性、方法和构造器。
下面我们就分别来看下,我们是如何通过反射机制来获取一个类的这些信息的。
1.获取属性
User user = new User();
Class cl = user.getClass();
Field[] fields1 = cl.getFields();
Field[] fields2 = cl.getDeclaredFields();
可以看到我们可以利用getFields()和getDeclaredFields()两个方法来获取类中的属性列表,那么这两个方法有什么区别呢?区别就是前者只会返回类的共有成员信息,而后者这会返回类中所有的成员信息包括公有的、私有的、受保护的,但是不包括父类的成员信息。
2.获取构造器
Constructor[] constructors1 = cl.getConstructors();
Constructor[] constructors2 = cl.getDeclaredConstructors();
3.获取方法
Method[] methods1 = cl.getMethods();
Method[] methods2 = cl.getDeclaredMethods();
可以看到我们可以通过一个类的Class对象很轻松的获取他的属性、构造器以及方法信息。但是在Field、Constructor以及Method中又分别提供了哪些api呢?下面我们就一起来看下。
1.getName()方法,用来获取对应的名称。同时存在于Field、Constructor以及Method类中。
2.getModifiers()方法来获取前面的修饰符(public等),但是getModifiers()返回的是一个int值,我们可以通过Modifier.toString(int i)将其转换成对应的字符串。也同样同时存在于Field、Constructor以及Method类中。
3.getParameterTypes()方法,用来获取方法的参数类型数组。存在于Constructor以及Method类中
4.getReturnType()方法,用来获取方法的返回类型。只存在于Method类中
有了这些api,我们就拥有了在运行时分析一个类的能力,我们可以通过一个简单的小例子来实践一下,我们可以编写一个方法来输出一个类的完整信息,具体的实现会在文末给出,大家可以先自己尝试一下。
利用反射查看对象
有些时候呢,我们可能也需要反射去获取对象中属性的值,比如说在导出Excel的时候,我们只知道列所对应属性的字段名称,然后我们需要通过反射获取它的值,然后把它写到Excel中。那么这节内容就一起来看下如何利用Java的反射机制来分析对象。
User user = new User(1,"itweknow");
Class cl = user.getClass();
Field userName = cl.getDeclaredField("userName");
Object value = userName.get(user);
就像上面的代码一样,我们可以使用Field类中提供的get(Object obj)方法来获取属性的值,对于基础类型还提供了特定的get方法,比如getDouble()。但是如果上面的userName是个私有属性的话,get()方法肯定会抛出IllegalAccessException的异常。这是时候我们需要使用setAccessible()方法覆盖安全管理器的访问控制。
User user = new User(1,"itweknow");
Class cl = user.getClass();
Field userName = cl.getDeclaredField("userName");
userName.setAccessible(true);
Object value = userName.get(user);
setAccessible()方法在Field、Method、Constructor类中都有提供。与get()方法呼应,Field还提供了set()方法用来给属性设置值。
利用反射调用任何方法
在Method类中提供了invoke()方法来调用,当前Method对象所包装的方法。invoke()方法的定义如下:
Object invoke(Object obj, Object... args)
第一个参数是调用这个方法的对象,第二个参数是该方法的参数,是一个数组的形式。下面我们就来看下如何利用反射来调用User类中的sayHello()方法吧。
Method sayHelloMethod = cl.getDeclaredMethod("sayHello", String.class);
sayHelloMethod.setAccessible(true);
sayHelloMethod.invoke(user, "Reflect");
看上面的代码我们通过getDeclaredMethod()方法来获取了一个名为sayHello的私有方法(PS:如果是公有方法的话直接使用getMethod()方法就可以了),同样对于私有方法,我们需要修改它的访问控制才能顺利调用。
API整理
上面的章节中提到了不少Java反射机制中提供的Api,下面是我整理的一些常用的反射Api,大家可以参考一下。
1.Class类
| Api | 描述 | 
|---|---|
| forName() | 返回指定类名的Class对象 | 
| newInstance() | 返回一个这个类的新实例 | 
| getFields() | 返回这个类所有的公有属性 | 
| getDeclaredField() | 返回这个类所有的属性(包含公有、私有、受保护) | 
| getMethods() | 返回这个类下所有的共有方法 | 
| getDeclaredMethods() | 返回这个类所有的方法(包含公有、私有、受保护) | 
| getConstructors() | 返回这个类所有公有的构造器 | 
| getDeclaredConstructors() | 返回这个类所有的构造器(包含公有、私有、受保护) | 
| getField() & getDeclaredField() | 返回这个类中指定名称的属性 | 
| getMethod() & getDeclaredMethod() | 返回指定名称和参数的方法 | 
| cl.getConstructor() & cl.getDeclaredConstructor() | 获取指定参数的构造器 | 
2.Field类
| Api | 描述 | 
|---|---|
| getModifiers() | 返回一个用于描述属性的修饰符的整型数值。使用 Modifier类中的toString()方法将其转为字符串。 | 
| getName() | 返冋一个用于描述属性名的字符串。 | 
3.Method类
| Api | 描述 | 
|---|---|
| getModifiers() | 返回一个用于描述方法的修饰符的整型数值。使用 Modifier类中的toString()方法将其转为字符串。 | 
| getName() | 返冋一个用于描述方法名的字符串。 | 
| getParameterTypes() | 返回一个用于描述参数类型的Class对象数组。 | 
| getReturnType() | 返回一个用于描述返H类型的Class对象。 | 
| invoke() | 调用这个对象所描述的方法, 传递给定参数,并返回方法的返回值。 | 
4.Constructor类
| Api | 描述 | 
|---|---|
| getModifiers() | 返回一个用于描述构造器的修饰符的整型数值。使用 Modifier类中的toString()方法将其转为字符串。 | 
| getName() | 返冋一个用于描述构造器名的字符串。 | 
| getParameterTypes() | 返回一个用于描述参数类型的Class对象数组。 | 
5.AccessibleObject类
| Api | 描述 | 
|---|---|
| setAccessible(boolean flag) | 为反射对象设置可访问标志。flag 为 true 表明屏蔽 Java 语言的访问检查,使得对象的私有属性也可以被査询和设置。 | 
| isAccessible() | 返回反射对象的可访问标志的值。 | 
结束语
这篇文章主要和大家一起了解了一下Java的反射机制,以及在反射包下Field、Method、Constructor三个类所提供的api。在利用反射分析类小节中,我提到了使用反射打印类的完整信息,具体的实现代码点击这里获取。希望这篇文章能够对大家有所帮助。最后,如果你喜欢这篇文章的话欢迎在Github源码项目点个Star。
PS:学习不止,码不停蹄!如果您喜欢我的文章,就关注我吧!
一文带你了解Java反射机制的更多相关文章
- 文末送书四本 | 这篇Java反射机制太经典!不看后悔!
		
先看再点赞,给自己一点思考的时间,如果对自己有帮助,微信搜索[程序职场]关注这个执着的职场程序员. 价值:Java技能,面试经验指导,简历优化,职场规划指导,技能提升方法,讲不完的职场故事,个人成长经 ...
 - Java反射机制(带应用)
		
1.Java的反射机制: Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态 ...
 - Java反射机制的学习
		
Java反射机制是Java语言被视为准动态语言的关键性质.Java反射机制的核心就是允许在运行时通过Java Reflection APIs来取得已知名字的class类的相关信息,动态地生成此类,并调 ...
 - Java反射机制深入研究
		
ava 反射是Java语言的一个很重要的特征,它使得Java具体了“动态性”. 在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法? ...
 - Java反射机制(转载)
		
原文链接:http://www.blogjava.net/zh-weir/archive/2011/03/26/347063.html Java反射机制是Java语言被视为准动态语言的关键性质.Jav ...
 - Java反射机制浅析
		
概念 Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语 ...
 - JAVA反射机制及理解
		
JAVA反射 往往当我们面对一项新的知识时,我们往往需要知道三个方面,它是什么,它能做什么,它比原有知识强在哪里,我们该怎么使用它.当你能够解决这些问题时,便意味着你已经对这项知识入门了. 首先: 反 ...
 - (转载)Java反射机制
		
Java反射机制是Java语言被视为准动态语言的关键性质.Java反射机制的核心就是允许在运行时通过Java Reflection APIs来取得已知名字的class类的相关信息,动态地生成此类,并调 ...
 - Java反射机制demo(三)—获取类中的构造函数
		
Java反射机制demo(三)—获取类中的构造函数 1,获取类中所有的构造函数 如下面的代码中所示,这个类中显式的构造函数有五个. 空构造: public UserInfo() 带参构造有四个: pu ...
 
随机推荐
- Java 函数传入参数后,究竟发生了什么?java函数传参数原理解析
			
JAVA函数在传入参数A时,会在函数作用周期内生成一个与参数相同类型的局部变量B. B与A指向同一块内存区域,并且具有相同的名字如param. 在函数内所有对param的操作都是对B的操作.对B进行赋 ...
 - SpringCloud系列——TX-LCN分布式事务管理
			
前言 SpringCloud分布式架构给我们带来开发上的便利,同时增加了我们对事务管理的难度,微服务的遍地开花,本地事务已经无法满足分布式的要求,由此分布式事务问题诞生. 分布式事务被称为世界性的难题 ...
 - Hadoop 三剑客之 —— 分布式计算框架 MapReduce
			
一.MapReduce概述 二.MapReduce编程模型简述 三.combiner & partitioner 四.MapReduce词频统计案例 4.1 项目简介 ...
 - 【vue系列】Virtual DOM 真的比操作原生 DOM 快吗?
			
一.前言 网上都说操作真实dom怎么怎么慢,这儿有个例子:http://chrisharrington.github.io/demos/performance/,例子循环2000个随机数组,点击按钮重 ...
 - Spring事务原理一探
			
概括来讲,事务是一个由有限操作集合组成的逻辑单元.事务操作包含两个目的,数据 一致以及操作隔离.数据一致是指事务提交时保证事务内的所有操作都成功完成,并且 更改永久生效:事务回滚时,保证能够恢复到事务 ...
 - Hadoop  ——  单机环境搭建
			
一.前置条件 Hadoop的运行依赖JDK,需要预先安装,安装步骤见: Linux下JDK的安装 二.配置免密登录 Hadoop组件之间需要基于SSH进行通讯. 2.1 配置映射 配置ip地址和主机名 ...
 - 系统学习 Java IO (三)----文件类 File
			
目录:系统学习 Java IO---- 目录,概览 Java IO API 中的 File 类可以访问基础文件系统. 使用 File 类,可以: 检查文件或目录是否存在. 如果目录不存在,创建一个目录 ...
 - composer简述
			
1.composer是一个php依赖管理工具,而不是一个包管理器.怎么来理解呢?就像在是在电脑中安装了个电脑管家,在电脑管家的软件管理中下载和更新软件,其实这个电脑管家只是一个管理工具,而真正的软件可 ...
 - rbash限制用户执行的命令
			
rbash限制用户执行的命令 软连接 sudo ln -s /bin/bash /bin/rbash sudo bash -c 'echo "/bin/rbash" >> ...
 - BZOJ 1878:[SDOI2009]HH的项链(莫队算法)
			
http://www.lydsy.com/JudgeOnline/problem.php?id=1878 题意:…… 思路:比上题还简单很多.数字很小,开一个数组哈希记录出现次数(记得数组要开1e6) ...