java反射机制如何获得(详解面试中常考的)(1)

反射(Reflection) 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性和方法。

反射是一项高级开发人员应该掌握的“黑科技”,其实反射并不是 Java 独有的,许多编程语言都提供了反射功能。在面试中面试官也经常对反射问题进行考察,反射是所有注解实现的原理,尤其在框架设计中,有不可替代的作用。

关于反射,常见的面试考察点包括:

本篇我们就一起来学习一下 Java 反射机制。

一、反射是什么?

反射的概念是由 Smith 在 1982 年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。

通俗地讲,一提到反射,我们就可以想到镜子。镜子可以明明白白地照出我是谁,还可以照出别人是谁。反映到程序中,反射就是用来让开发者知道这个类中有什么成员,以及别的类中有什么成员。

二、为什么要有反射

有的同学可能会疑惑,Java 已经有了封装为什么还要有反射呢?反射看起来像是破坏了封装性。甚至让私有变量都可以被外部访问到,使得类变得不那么安全了。

我们来看一下 Oracle 官方文档中对反射的描述:

Uses of Reflection

Reflection is commonly used by programs which require the ability to examine or modify the runtime behavior of applications running in the Java virtual machine. This is a relatively advanced feature and should be used only by developers who have a strong grasp of the fundamentals of the language. With that caveat in mind, reflection is a powerful technique and can enable applications to perform operations which would otherwise be impossible.

从 Oracle 官方文档中可以看出,反射主要应用在以下几方面:

也就是说,Oracle 希望开发者将反射作为一个工具,用来帮助程序员实现本不可能实现的功能(perform operations which would otherwise be impossible)。正如《人月神话》一书中所言:软件工程没有银弹。很多程序架构,尤其是三方框架,无法保证自己的封装是完美的。如果没有反射,对于外部类的私有成员,我们将一筹莫展,所以我们有了反射这一后门,为程序设计提供了更大的灵活性。工具本身并没有错,关键在于如何正确地使用。

三、反射 API

Java 类的成员包括以下三类:属性字段、构造函数、方法。反射的 API 也是与这几个成员相关:

java反射机制如何获得(详解面试中常考的)(2)

接下来,我们通过一个典型的例子来学习反射。

先做准备工作,新建 com.test.reflection 包,在此包中新建一个 Student 类:

java反射机制如何获得(详解面试中常考的)(3)

可以看到,Student 类中有两个 字段、两个 构造方法、两个 函数,且都是一个私有,一个公有。由此可知,这个测试类基本涵盖了我们平时常用的所有类成员。

3.1.获取 Class 对象的三种方式

获取 Class 对象有三种方式:

java反射机制如何获得(详解面试中常考的)(4)

通过这三种方式获取到的 Class 对象是同一个,也就是说 Java 运行时,每一个类只会生成一个 Class 对象。

我们将其打印出来测试一下:

java反射机制如何获得(详解面试中常考的)(5)

运行程序,输出如下:

java反射机制如何获得(详解面试中常考的)(6)

OK,拿到 Class 对象之后,我们就可以为所欲为啦!

3.2.获取成员变量

获取字段有两个 API:getDeclaredFields 和 getFields。他们的区别是: getDeclaredFields 用于获取所有声明的字段,包括公有字段和私有字段,getFields 仅用来获取公有字段:

java反射机制如何获得(详解面试中常考的)(7)

运行程序,输出如下:

java反射机制如何获得(详解面试中常考的)(8)

3.3.获取构造方法

获取构造方法同样包含了两个 API:用于获取所有构造方法的 getDeclaredConstructors和用于获取公有构造方法的 getConstructors:

java反射机制如何获得(详解面试中常考的)(9)

运行程序,输出如下:

java反射机制如何获得(详解面试中常考的)(10)

3.4.获取非构造方法

同样地,获取非构造方法的两个 API 是:获取所有声明的非构造函数的 getDeclaredMethods 和仅获取公有非构造函数的 getMethods:

java反射机制如何获得(详解面试中常考的)(11)

运行程序,输出如下:

java反射机制如何获得(详解面试中常考的)(12)

从输出中我们看到,getMethods方法不仅获取到了我们声明的公有方法 setStudentAge,还获取到了很多 Object 类中的公有方法。这是因为我们前文已说到:Object 是所有 Java 类的父类。所有对象都默认实现了 Object 类的方法。 而 getDeclaredMethods是无法获取到父类中的方法的。

四、实践

学以致用,让我们来一个实际的应用感受一下。还是以 Student 类为例,如果此类在其他的包中,并且我们的需求是要在程序中通过反射获取他的构造方法,构造出 Student 对象,并且通过反射访问他的私有字段和私有方法。那么我们可以这样做:

java反射机制如何获得(详解面试中常考的)(13)

程序的逻辑注释已经写得很清晰了,我们再梳理一下:

  1. 先用第一种全路径获取 Class 的方法获取到了 Student 的 Class 对象
  2. 然后反射调用它的私有构造方法 private Student(String studentName),构建出 newInstance
  3. 再将其公有字段 studentAge 设置为 10
  4. 最后反射调用其私有方法 show,传入参数 “message”,并打印出这个方法的返回值。

其中,setAccessible 函数用于动态获取访问权限,Constructor、Field、Method 都提供了此方法,让我们得以访问类中的私有成员。

运行程序,输出如下:

java反射机制如何获得(详解面试中常考的)(14)

互动话题

本篇文章主要介绍了基本 Java 反射机制的重要内容,你在面试中有被问到过其他关于反射的面试考点么?不妨在评论区告诉我们哦~

本文作者:Alpinist Wang

声明:本文归 “力扣” 版权所有,如需转载请联系。文章封面图来源于网络,为非商业用途使用,如有侵权联系删除。

,