Java 中的反射是什么
反射是一个程序语言用来自检和修改自身结构和行为的过程。
这么说可能有些晦涩,反射可以理解为在程序运行过程中,获取程序的结构信息,从而根据不同的情况来调整程序的行为。
在使用汇编语言编程的时代,汇编语言可以直接获取任何信息,可以认为汇编语言天然就支持反射。但是到后来的一些高级语言,比如 Fortran 和 C 语言等等,由于不支持反射,也就无法获取信息。
再到后续的 Java,C# 等语言中都自带了反射框架,这些语言就可以通过反射来实现通用的框架,比如在 Java 的 Spring 中就大量使用了反射。
这篇文章重点介绍 Java 中的反射。
💡本文基于 OpenJDK11
1. 反射能干什么
在 Java 中,反射可以获取类的定义、属性和方法,并且可以调用这些方法,或者构造对象,甚至可以在运行时修改类的定义。
先来看一个简单的例子,通过这个例子可以知道反射能做什么,例子中的代码下面会详细讲解:
使用反射来生成 ArrayList
对象并调用方法:
如果不使用反射,这个代码很简单:
反射这么麻烦,为什么还要使用它?
观察一下上面利用反射来执行方法的代码可以发现,执行任何类的方法,那段代码都不需要修改,而且更重要的是,具体执行的方法还可以在程序运行的过程中改变。
反射用起来虽然麻烦,但是反射的动态性提高了 Java 的灵活性,很多框架都依赖反射。
2. 相关概念
在 Java 中,有很多的类,每个类都有自己的属性,方法,构造函数等等信息,这些信息都需要通过一种方式表示,在 Java 中就是通过 Class 对象来表示。
这里不要把 Class 与 Object 混在一起,Object 是所有类的父类,而 Class 类则不一样,在每个类中,都有一个 Class 对象来保存类的信息。即使对于 Java 中的原生数据类型,也有自己的 class 对象。
每个 Class 对象中都有主要有三个主要部分:Field、Method 和 Constructor。这些和反射相关的类都在 java.lang.reflect 包下。
Method 和 Constructor 在上面的代码中都看到了,分别表示类的方法和构造函数。Field 则表示类的属性。
除了上面这些信息外,还有其他的信息,比如判断属性或者方法是否能访问,获取类、方法、属性的注解等等:
即使对于私有方法或者属性,也可以通过下面的方式来访问:
在 Java 中,注解用的很多,实际上,注解本身并没有包含额外的内容,只是起到标记的作用,所有的注解都可以通过反射来获取,然后再进行相应的逻辑处理。
还可以获取方法的参数,返回值的类型等等信息。
所以总的来说,反射是一个框架,可以帮助获取程序内部的信息,至于获取这些信息来做什么,就看开发人员的发挥。
反射虽然很强大,但是性能上相比于普通方式性能上难免会有一些损失,需要注意,在程序执行的过程中,需要尽量少用反射。而且反射连私有方法都可以访问,如果滥用就可能造成程序的不安全。
3. 反射的基本用法
使用行业的第一步,就是获取目标类型的 Class 对象,如果获取不到,那就说明目标类型无法完成类加载,也就不能进行后续的反射操作。
获取 Class 对象的方法
有 4 种方法可以获取 Class 对象。
通过类的 class 属性:
通过 Class.forName() 方法:
通过对象的 getClass() 方法:
对于基本类型的包装类,还有一种方法可以获取 Class 对象:
创建对象
在获取到 Class 对象之后就可以创建对象了,创建对象有两种方式。
通过 Class 对象直接生成:
通过构造函数生成:
如果构造函数有参数:
调用方法
在生成了对象之后,自然就可以调用方法,调用的方式和上面的代码一样。
首先获取 Method,如果方法没有参数,直接获取执行就可以:
如果有参数,在获取方法的时候就需要声明方法的类型和个数,而且参数的顺序不能乱:
其他工具方法
上面是反射的一些基本用法,当然反射也提供了其他的一些工具方法。
获取所有已经声明的属性、方法和构造函数,包括 private
的也会被获取出来:
判断是否是内部类:
还有其他判断是否接口、注解,获取类的泛型信息等等方法。
文 / Rayjun
本文首发于微信公众号
REF
[1] https://en.wikipedia.org/wiki/Reflection_(computer_programming)
版权声明: 本文为 InfoQ 作者【Rayjun】的原创文章。
原文链接:【http://xie.infoq.cn/article/251320e1fabd93a41e6cea60a】。文章转载请联系作者。
评论