简述
Java
的反射机制及其应用场景
反射(
Reflection
) 是
Java
程序开发语言的特征之一,它允许运行中的
Java
程序对自身进行检查,或者说“
自审
”
,并能直接操作程序的内部属性和方法。
反射是一项高级开发人员应该掌握的
“
黑科技
”
,其实反射并不是
Java
独有的,许多编程语言都提供了反 射功能。在面试中面试官也经常对反射问题进行考察,反射是所有注解实现的原理,尤其在框架设计 中,有不可替代的作用。关于反射,常见的面试考察点包括:
如何反射获取
Class
对象
如何反射获取类中的所有字段
如何反射获取类中的所有构造方法
如何反射获取类中的所有非构造方法
反射主要应用在以下几方面:
反射让开发人员可以通过外部类的全路径名创建对象,并使用这些类,实现一些扩展的功能。
反射让开发人员可以枚举出类的全部成员,包括构造函数、属性、方法。以帮助开发者写出正确的
代码。
测试时可以利用反射
API
访问类的私有成员,以保证测试代码覆盖率。
也就是说,
Oracle
希望开发者将反射作为一个工具,用来帮助程序员实现本不可能实现的功能
(
perform operations which would otherwise be impossible
)。正如《人月神话》一书中所言:软
件工程没有银弹。很多程序架构,尤其是三方框架,无法保证自己的封装是完美的。如果没有反射,对于外部类的私有成员,我们将一筹莫展,所以我们有了反射这一后门,为程序设计提供了更大的灵活性。工具本身并没有错,关键在于如何正确地使用。

3.1
获取
Class
对象的三种方式
获取
Class
对象有三种方式:
第一种方法是通过类的全路径字符串获取
Class
对象,这也是我们平时最常用的反射获取
Class
对
象的方法;
第二种方法有限制条件:需要导入类的包;
第三种方法已经有了
Student
对象,不再需要反射。
通过这三种方式获取到的
Class
对象是同一个,也就是说
Java
运行时,每一个类只会生成一个
Class
对象。
// 1.
通过字符串获取
Class
对象,这个字符串必须带上完整路径名
Class studentClass
=
Class
.
forName
(
"com.test.reflection.Student"
);
// 2.
获取声明的构造方法,传入所需参数的类名,如果有多个参数,用
','
连接即可
Constructor studentConstructor
=
studentClass
.
getDeclaredConstructor
(
String
.
class
);
//
如果是私有的构造方法,需要调用下面这一行代码使其可使用,公有的构造方法则不需要下面这一行代码
studentConstructor
.
setAccessible
(
true
);
//
使用构造方法的
newInstance
方法创建对象,传入构造方法所需参数,如果有多个参数,用
','
连接即可
Object
student
=
studentConstructor
.
newInstance
(
"NameA"
);
// 3.
获取声明的字段,传入字段名
Field studentAgeField
=
studentClass
.
getDeclaredField
(
"studentAge"
);
//
如果是私有的字段,需要调用下面这一行代码使其可使用,公有的字段则不需要下面这一行代码
// studentAgeField.setAccessible(true);
//
使用字段的
set
方法设置字段值,传入此对象以及参数值
studentAgeField
.
set
(
student
,
10
);
// 4.
获取声明的函数,传入所需参数的类名,如果有多个参数,用
','
连接即可
Method studentShowMethod
=
studentClass
.
getDeclaredMethod
(
"show"
,
String
.
class
);
//
如果是私有的函数,需要调用下面这一行代码使其可使用,公有的函数则不需要下面这一行代码
studentShowMethod
.
setAccessible
(
true
);
//
使用函数的
invoke
方法调用此函数,传入此对象以及函数所需参数,如果有多个参数,用
','
连接即可。
函数会返回一个
Object
对象,使用强制类型转换转成实际类型即可
Object
result
=
studentShowMethod
.
invoke
(
student
,
"message"
);
System
.
out
.
println
(
"result: "
+
result
);
Version:0.9 StartHTML:0000000105 EndHTML:0000004975 StartFragment:0000000141 EndFragment:0000004935
Bean
的生命周期
我们需要明确的是,在这里我们的
Bean
的生命周期主要指的是
singleton bean
,对
prototype bean
来说,当用户
getBean
获得
prototype bean
的实例后,
IOC
容器就不再对当前实例进行管理,而是把管 理权交由用户,此后再getBean
生成的是新的实例。对于
request/session/application/websocket
这几
种
scope
的
bean
我们在此不谈。 在不同的容器中,Bean
的生命周期开始的时间不同。对于
ApplicationContext
来说,当容器启动的时候,bean
就已经实例化了。而对于
BeanFactory
来说,直到调用
getBean()
方法的时候才进行实例化。