反射主要应用在以下几方面:
反射让开发人员可以通过外部类的全路径名创建对象,并使用这些类,实现一些扩展的功能。
反射让开发人员可以枚举出类的全部成员,包括构造函数、属性、方法。以帮助开发者写出正确的
代码。
测试时可以利用反射 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() 方法的时候才进行实例化。