Java反射

来源:互联网 发布:如何申请网络域名 编辑:程序博客网 时间:2024/05/20 17:59

Java反射

什么是反射

Oracle官方解释:

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.
反射通常被用在需要检查和修改运行在JVM上的应用的运行时行为的程序中。

但是这个概念通常和反思(introspection)混淆
下面看看wiki对Reflection和Introspection的定义:

  1. Introspection is the ability of a program to examine the type or properties of an object at runtime(反思是一种被程序用来在运行时检测对象的类型和属性的能力)。
  2. Reflection is the ability of a program to examine and modify the structure and behavior of an object at runtime(反射是一种被程序用来在运行时检测和修改对象的结构和行为的能力)

从定义中可以看出,反思是反射的子集,一些编程语言支持introspection,但是不支持反射,例如:C++.
在Java中,反射更接近于反思,因为不能修改对象的结构,有些API可以修改方法和字段的访问权限,但是没有提供修改结构的API。

为什么需要反射?

反射提供了一下功能:

  1. 在运行时检测对象的类
  2. 在运行时为类构建一个对象
  3. 在运行时检测类的方法和字段
  4. 在运行时调用一个对象的任意方法
  5. 在运行时修改构造函数,方法和字段的访问权限

动态代理基于反射实现。
在框架中都会用到反射。
例如,在运行单元测试时,JUnit运用反射查找被@Test注解标记的方法,然后执行这些方法。
在web框架(如Spring),定义自己的类和接口的实现,让后配置到配置文件中,使用反射,可以快速的动态实例化需要的类。

<bean id="someID" class="com.bao.Foo">    <property name="someField" value="someValue" /></bean>

当Spring上下文处理这个< bean >元素时,会使用参数“com.bao.Foo”调用Class.forName(String)方法实例化Class对象,然后再次使用反射根据< property >元素的name值得到set方法并且设置指定的value值。

在Servlet web应用程序中也使用同样的机制:

<servlet>    <servlet-name>someServlet</servlet-name>    <servlet-class>com.programcreek.WhyReflectionServlet</servlet-class><servlet>

怎么使用反射

Class对象是Java反射操作的源头

Class反射机制

指的是可以在运行时加载探知和使用在编译期间完全未知的类。
每个类被加载进入内存之后都会生成一个对应的java.lang.Class对象,包含了整个类的结构信息,Class对象是用来创建这个类的所有对象。

Class对象的获取

  • Class.forName(“类的完全限定名”)动态加载类(最常用)
  • 对象.getClass()
  • 类的.class(最安全,性能最好)属性

从Class对象中可以获取到类的信息的相关方法参考JDK文档

通过反射可以得到Class对象中的Method,Constructor,Field这些类都实现了java.lang.reflect.Member接口,程序可以通过Method对象执行一个实例的相应的方法,通过Constructor对象来调用相应的构造函数创建实例,通过Field对象来获取或者设置一个实例对应的字段的值。

通过反射创建对象

反射创建对象两种方式:

  • Class对象的.newInstance()方法,这种方式使用类的默认构造函数,因此也要求类提供默认构造函数,否则报错
  • 从Class对象中获取Constructor对象,再调用Constructor的newInstance()方法来创建

一般我们通过new关键字实例化一个类对象,现在又多了一个反射机制,和new关键字方式相比有什么不同?出现的意义又是什么?
答案就是为了实现软件设计的解耦合,降低耦合度的最好方式是使用接口,但是使用接口也逃不过new关键字创建对象,实际上new关键字是造成耦合的关键。

如果一个类A依赖于另外一个类B,在使用new关键字创建一个具体的A对象时需要先new实例化一个B对象,然后new实例化A对象,调用A对象的set方法,这是传统的方式,但是弊端很明显,即A对象对B对象的依赖必须通过代码的方式设置,如果想要修改依赖,必须修改代码才能实现,无法通过配置文件方式灵活配置。

但是通过反射的机制就可以实现依赖的可配置化,因为可以通过配置的字段名称去找到Class对象的Method对象,然后Method对象设置通过Class实例化的实例的依赖,所有依赖的配置都可以用一套代码实现,不论依赖有多复杂,只需要保证配置文件的格式正确即可。Spring的IOC模块就是基于这种思想实现。

0 0
原创粉丝点击