初探Java反射机制
反射库提供了一个非常丰富且精心设计的工具集,以便编写能够动态操纵java代码的程序库。这项功能被大量地应用于JavaBeans中。反射机制提供了在运行状态中获得和调用修改任何一个类的属性和方法的能力。
Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。
首先让我们来看一个简单的小程序,感性的认识一下Java反射机制:
1 import java.lang.reflect.*; 2 3 public class reflection { 4 public static void main(String args[]) { 5 try { 6 Class c = Class.forName("java.util.Stack"); 7 Method m[] = c.getDeclaredMethods(); 8 9 for (int i = 0; i < m.length; i++) 10 System.out.println(m[i].toString()); 11 } 12 catch (Throwable e){ 13 System.err.println(e); 14 } 15 } 16 }
输出结果为:
public synchronized java.lang.Object java.util.Stack.pop() public java.lang.Object java.util.Stack.push(java.lang.Object) public boolean java.util.Stack.empty() public synchronized java.lang.Object java.util.Stack.peek() public synchronized int java.util.Stack.search(java.lang.Object)
上述代码通过Java反射机制列出了java.util.Stack 类的各方法名以及它们的限制符和返回类型。接下来,让我们详细分析一下Java反射机制的原理和使用。
Class类
要了解Java反射机制,首先必须得了解Class类。在程序运行期间,Java运行时系统始终为所有的对象维护一个被成为运行时的类型标识,这个信息跟踪着每个对象所属的类。虚拟机利用运行时信息选择相应的方法执行。保存这些信息的类被称为Class,这个名字很容易让人混淆。下面来看一个例子:
1 package Reflect; 2 3 /** 4 * 通过一个对象获得完整的包名和类名 5 * */ 6 class Demo{ 7 //other codes... 8 } 9 10 class hello{ 11 public static void main(String[] args) { 12 Demo demo=new Demo(); 13 System.out.println(demo.getClass().getName()); 14 } 15 }
每个类中所包含的getClass()方法将会返回一个Class类的实例(getClass方法被定义在Object类中,Object类是所有类的祖先),最常用的Class方法是getName。这个方法将返回类的名字,如果类在某个包中,包的名字也作为类名的一部分返回。这也是获得Class对象的第一种方法。
运行结果:Reflect.Demo
还可以调用Class类的静态方法forName获得类名对应的Class对象:
String className = "java.util.Date";
Class cl = Class.forName(className);
注意,className一定要包含包的路径。这是获得Class对象的第二种方法。
这边再强调一下,Class类对象保存了每个对象所属类的信息,下面会讲到,通过Class类对象也可以创建一个相应类(Class保存信息的类)的实例,即某个对象。
获得Class类对象的第三种方法很简单。如果T是任意的Java类型,T.class将代表匹配的对象。例如:
Class cl1 = Date.class; Class cl2 = int.class; Class cl3 = Double[].class;
一个Class对象实际上表示的是一个类型,而这个类型未必一定是一种类。例如,int不是类,但int.class是一个Class类型的对象。
通过newInstance()函数可以快速地创建一个类的实例:
1 package Reflect; 2 3 class Person{ 4 5 public String getName() { 6 return name; 7 } 8 public void setName(String name) { 9 this.name = name; 10 } 11 public int getAge() { 12 return age; 13 } 14 public void setAge(int age) { 15 this.age = age; 16 } 17 @Override 18 public String toString(){ 19 return "["+this.name+" "+this.age+"]"; 20 } 21 22 private String name; 23 private int age; 24 } 25 26 class hello{ 27 public static void main(String[] args) { 28 Class<?> demo=null; 29 try{ 30 demo=Class.forName("Reflect.Person"); 31 }catch (Exception e) { 32 e.printStackTrace(); 33 } 34 Person per=null; 35 try { 36 per=(Person)demo.newInstance(); 37 } catch (InstantiationException e) { 38 e.printStackTrace(); 39 } catch (IllegalAccessException e) { 40 e.printStackTrace(); 41 } 42 per.setName("Rollen"); 43 per.setAge(20); 44 System.out.println(per); 45 } 46 }
运行结果:[Rollen 20]
注意,newInstance方法调用默认的构造器初始化新创建的对象,如果这个类没有默认的构造器,就会抛出一个异常:
java.lang.InstantiationException: Reflect.Person
at java.lang.Class.newInstance0(Class.java:340)
at java.lang.Class.newInstance(Class.java:308)
at Reflect.hello.main(hello.java:39)
Exception in thread "main" java.lang.NullPointerException
at Reflect.hello.main(hello.java:47)
利用反射分析类的能力
在java.lang.reflect包中有三个类Field、Method和Constructor分别用于描述类的域、方法和构造器。这三个类都有一个叫做getName的方法,用来返回项目的名称。Field类有一个getType方法,用来返回描述域所属类型的Class对象。Method和Constructor类有能够报告参数类型的方法,Method类还有一个可以报告返回类型的方法。这三个类还有一个叫做getModifiers的方法,它将返回一个整数,用不同的位开关描述public和static这样的修饰符使用状况。
Class类中的getFields、getMethods和getConstructors方法将分别返回类提供的public域、方法和构造器数组,其中包括超类的共有成员。Class类的getDeclareFields、getDeclareMethods和getDeclareConstructors方法将分别返回类中声明的全部域、方法和构造器,包括私有成员和受保护成员,但不包括超类的成员。
下面看一个通过Class调用其他类中的构造函数的例子:
1 package Reflect; 2 3 import java.lang.reflect.Constructor; 4 5 class Person{ 6 public Person() { 7 } 8 public Person(String name){ 9 this.name=name; 10 } 11 public Person(int age){ 12 this.age=age; 13 } 14 public Person(String name, int age) { 15 this.age=age; 16 this.name=name; 17 } 18 public String getName() { 19 return name; 20 } 21 public int getAge() { 22 return age; 23 } 24 @Override 25 public String toString(){ 26 return "["+this.name+" "+this.age+"]"; 27 } 28 private String name; 29 private int age; 30 } 31 32 class hello{ 33 public static void main(String[] args) { 34 Class<?> demo=null; 35 try{ 36 demo=Class.forName("Reflect.Person"); //Demo中保存了Person类的信息,包括域、方法和构造器 37 }catch (Exception e) { 38 e.printStackTrace(); 39 } 40 Person per1=null; 41 Person per2=null; 42 Person per3=null; 43 Person per4=null; 44 //取得全部的构造函数 45 Constructor<?> cons[]=46 try{ 47 per1=(Person)cons[0].newInstance(); 48 per2=(Person)cons[1].newInstance("Rollen"); 49 per3=(Person)cons[2].newInstance(20); 50 per4=(Person)cons[3].newInstance("Rollen",20); 51 }catch(Exception e){ 52 e.printStackTrace(); 53 } 54 System.out.println(per1); 55 System.out.println(per2); 56 System.out.println(per3); 57 System.out.println(per4); 58 } 59 }
返回一个实现类的接口:
1 package Reflect; 2 3 interface China{ 4 public static final String name="Rollen"; 5 public static int age=20; 6 public void sayChina(); 7 public void sayHello(String name, int age); 8 } 9 10 class Person implements China{ 11 public Person() { 12 13 } 14 public Person(String sex){ 15 this.sex=sex; 16 } 17 public String getSex() { 18 return sex; 19 } 20 public void setSex(String sex) { 21 this.sex = sex; 22 } 23 @Override 24 public void sayChina(){ 25 System.out.println("hello ,china"); 26 } 27 @Override 28 public void sayHello(String name, int age){ 29 System.out.println(name+" "+age); 30 } 31 private String sex; 32 } 33 34 class hello{ 35 public static void main(String[] args) { 36 Class<?> demo=null; 37 try{ 38 demo=Class.forName("Reflect.Person"); 39 }catch (Exception e) { 40 e.printStackTrace(); 41 } 42 //保存所有的接口 43 Class<?> intes[]=demo.getInterfaces(); 44 for (int i = 0; i < intes.length; i++) { 45 System.out.println("实现的接口 "+intes[i].getName()); 46 } 47 } 48 }
运行结果:
实现的接口 Reflect.China