Java的反射机制


前言

能够分析类能力的程序称为反射。Java中反射机制十分强大,反射机制可以用来:
•在运行时分析类的能力。
•在运行时查看对象,例如,编写一个 toString 方法供所有类使用。
•实现通用的数组操作代码。
•利用Method对象,通过Method对象调用运行时类的方法。
•以及在SSM框架等注入JavaBean对象等等操作

一、Class类

使用反射,必须要了解什么是Class类。
在运行时系统始终为所有对象维护一个被称为运行时的类型标识。这个信息跟踪着每个对象所属的类。而保存这些信息的类称为Class。这个Class类的实例对象可以提供对应类本身的信息,比如有几种构造方法,有多少数据域,有什么行为方法等。
看代码(编码过程中有些方法的使用需要捕获异常,为了方便阅读我全部都抛出去了):

1.  /** 
2.	 * 现在有一个测试类,其中有数据域和行为方法 
3.	 */  
4.	public class ReflectiveTest {  
5.	    private String name;  
6.	    private int data;  
7.	    public ReflectiveTest() {}  
8.	    public ReflectiveTest(String name, int data) {  
9.	        this.name = name;  
10.	        this.data = data; }  
11.	    public String getName() {  
12.	        return name;}  
13.	    public void setName(String name) {  
14.	        this.name = name; }  
15.	    public int getData() {  
16.	        return data;}  
17.	    public void setData(int data) {  
18.	        this.data = data;}  
19.	} 

main方法中:

20.	//创建测试类的对象  
21.	ReflectiveTest t = new ReflectiveTest();  
22.	/** 
23.	 * 获取Class实例对象有几种方法: 
24.	 * 1.是通过类对象.getClass方法 
25.	 * 2.是通过类名.class 
26.	 * 3.是通过Class.forName(类名),
27.  * 如果类名保存在字符串中,并可在运行中改变,就可以使用这个方法获取
28.	 * 第三种方法可能会抛ClassNotFoundException(没有这个类)异常,这里我直接抛出去了 
29.	 */  
30.	Class clazz = t.getClass();  
31.	Class clazz2 = ReflectiveTest.class;  
32.	Class clazz3 = Class.forName("ReflectiveTest");  
33.	//这个几个Class实例对象就保留了ReflectiveTest类中所有的信息

请注意,一个Class对象实际上表示的是一个类型,而这个类型未必一定是一种类。例如,int不是类, 但int.class是一个Class类型的对象。

Class类常用的方法有getName,用于返回类名:

/** 
2.	 * 一个 Class 对象将表示一个特定类的属性。最常用的Class方法是getName()。这个方法将返回类的名字 
3.	 * 如果类在一个包里,那么包的名字也会作为类的名字一起出现(这里就不演示了) 
4.	 */  
5.	System.out.println(clazz.getName());//返回类的名字:ReflectiveTest

Class类还有一个常用的方法是newInstance()方法,这个方法能够动态的根据运行时类的空参构造器创造一个类对象,也可以使用 Constructor 类中的 newlnstance 方法调用对应的有参构造方法:

1.	/** 
2.	 * 一个 Class 对象将表示一个特定类的属性。最常用的Class方法是getName()。这个方法将返回类的名字 
3.	 * 如果类在一个包里,那么包的名字也会作为类的名字一起出现(这里就不演示了) 
4.	 */  
5.	System.out.println(clazz.getName());//返回类的名字:ReflectiveTest  
6.	  
7.	/** 
8.	 * Class常用方法:newInstance():调用空参构造器创建对应类对象 
9.	 * 如果想要调用有参构造器,必须先获取Constructor类对象,然后再调用对应的newInstance方法 
10.	 */  
11.	Object o = clazz.newInstance();//无参构造  
12.	//返回一个ReflectiveTest类对象(Object是所有类的父类,因此可以用Object类引用指向该对象)  
13.	//Class.getConstructors()按顺序返回类中所有构造器方法,下标从0开始  
14.	Constructor[] constructor = clazz.getConstructors();  
15.	//根据有参构造器创建一个ReflectiveTest类对象,name="test1",data=1  
16.	Object test1 = constructor[1].newInstance("test1", 1);  

二、利用反射检查类的结构

Java反射类库中有三个类Field、Method和Constructor分别用于描述类的数据域、方法和构造器。这三个类都有一个叫做getName的方法,用来返回对应类的名称,同时还有一些比较常用的方法等。看代码:

1.	/** 
2.	 * Field、Method、Constructor对象的获取和一些常用方法的使用 
3.	 */  
4.	//返回类中的定义的所有数据域(包括私有),返回顺序不一定按照定义顺序
5.	Field[] fields = clazz.getDeclaredFields();
6.	//返回类中定义的所有方法,返回顺序不一定按照定义顺序
7.	Method[] methods = clazz.getDeclaredMethods();
8.	//返回类中定义的所有构造方法,返回顺序不一定按照定义顺序
9.	Constructor[] constructors = clazz.getConstructors();
10.	//Field.getType方法,用来返回描述域所属类型的Class对象  
11.	System.out.println(fields[0].getType());//输出第一个数据与的类型名称:class java.lang.String(String类型)  
12.	  
13.	for (Method method : methods) {  
14.	    System.out.println(method.getReturnType());  
15.	    //这个方法是返回的是Method对象的泛型参数,如果没有泛型,则返回长度为0的数组  
16.	    //这个类中没有使用泛型的方法,所以全部都是长度为0的数组  
17.	    TypeVariable[] typeParameters = method.getTypeParameters();  
18.	    System.out.println(typeParameters.length);  
19.	    for (int j = 0;j < typeParameters.length;j++){  
20.	        System.out.print(typeParameters[j].getName()+" ");  
21.	    }  
22.	    System.out.println();  
23.	}  
24.	  
25.	/** 
26.	 * 这三个类还有一个叫做 getModifiers 的方法,它将返回一个整型数值, 
27.	 * 用不同的位开关描述public和static等这样的修饰符使用状况 
28.	 * 例如, 可以使用 Modifier 类中的 isPublic、 isPrivate 或 isFinal 
29.	 * 判断方法或构造器是否是 public、 private 或 final。 我们需要做的全部工作就是调用 Modifier 
30.	 * 类的相应方法,并对返回的整型数值进行分析,另外,还可以利用 Modifier.toString方法将 
31.	 * 修饰符打印出来 
32.	 */  
33.	System.out.println(fields[0].getModifiers());  
34.	System.out.println(Modifier.isPrivate(fields[0].getModifiers()));  
35.	System.out.println(methods[0].getModifiers());  
36.	System.out.println(Modifier.isPublic(methods[0].getModifiers()));

在通过Field或者Method等方法获取类信息时,如果是类中私有的属性或者方法,使用前必须通过setAccessible方法,如x. setAccessible(true)调用方法之后,才能够使用类中私有的方法和属性,否则会报错。

三、调用任意方法

在上面的讨论中,我们知道了Method可以获取类中定义的方法,但是如果调用类中的这些方法呢?我们可以使用Method类提供的invoke函数来调用对应的方法。
Invoke函数签名如下:
Object invoke(Object obj, Object… args)
第一个参数obj是隐式参数,其余的对象(可变长参数args)提供了显式参数。(在Java SE 5.0以前的版本中,必须传递一个对象数组,如果没有显式参数就传递一个null)。对于静态方法,第一个参数可以被忽略,即可以将它设置为null。

1.	//调用setName方法重新设置名字  
2.	methods[2].invoke(t,"test2");  
3.	System.out.println(t.getName());//输出test2

总结

这篇文章只记录了我初学反射时个人的一些见解。有些方法和概念还得要参考api文档以及其他资料等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值