Java反射机制浅析
什么是Java反射机制
Java反射机制主要用到了java.lang.reflect包下面的类。
首先来看下Java官方api中是怎么描述reflect包的:
Provides classes and interfaces for obtaining reflective information about classes and objects. Reflection allows programmatic access to information about the fields, methods and constructors of loaded classes, and the use of reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions.
简单翻译一下就是:
提供类和接口,以获得关于类和对象的反射信息。在安全限制内,反射允许编程访问关于加载类的字段、方法和构造方法的信息,并允许使用反射字段、方法和构造方法对其底层对等项进行操作。
哪里用到反射机制
有些同学做Java开发好两、三年了都觉得平常好像没有遇到过反射机制,可能平常大家已经在开发过程中接触或使用到了,只是没意识到而已。
举两个例子:
(1)JDBC连接
try { Class.forName("com.mysql.jdbc.Driver") ; } catch(ClassNotFoundException e) { System.out.println("找不到驱动程序类 ,加载驱动失败!"); return; }
与数据库同学打过交道的同学肯定对上述代码不陌生, Class.forName方法就是典型的java反射机制用法,通过类名称“反射”出类的信息。
(2)Spring
<bean id="userManager" class="com.blog.manager.impl.UserManagerImpl" />
用过spring的同学对xml中的bean配置肯定都知道,虽然在程序中我们没有显示的写代码去加载类,但spring框架已经在背后默默使用Java反射机制替我们都完成了。
现在很多开框架都用到反射机制,hibernate、struts都是用反射机制实现的。
为什么要使用反射机制
这篇文章介绍的不错
文中从Java的跨平台的特点引出了元对象的概念,有了元对象,Reflection也成了一件顺其自然的事情。有了Reflection,Java也就拥有了动态扩展的能力,这样就可以极大的提高程序的灵活性。
还有一个角度是用解耦性来看,例如spring等框架通过配置文件将类的加载名称和具体加载类进行分类,而Java反射机制天然支持通过类名加载类,所以在框架性的产品或中间件中Java反射机制有广阔的应用空间。
Reflection APIs
Java反射API为我们提供了使用反射机制的方法,可以探索和了解class的结构、如何对某个“运行时才获知名称的class”生成一份实体、为其fields赋值、调用其methods等。下面就具体介绍这些方法。
Class类
Class类在java.lang包下,从其api中可以看出:Class没有公共构造方法,Class对象在加载类时只能由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造。
Class has no public constructor. Instead Class objects are constructed automatically by the Java Virtual Machine as classes are loaded and by calls to the defineClass method in the class loader.
众所周知,Java有一个根类Object,它是所有Java类的继承根源,在其内部声明了数个应该在所有Java类中被改写的方法: hashCode()、equals()、clone()、toString()、getClass()等。
Class类十分特殊,他和一般类一样继承自Object,其实体用以表达Java程序运行时的类和接口,也用来表达enum、array、primitive Java types(boolean, byte, char, short, int, long, float, double)以及关键词void。当一个类被加载,或当加载器(calss loader)的defineClass()被JVM调用,JVM便自动产生一个Class对象。
Class是Reflect故事的起源,针对任何你想探勘的class,唯有先为它产生一个Class对象,接下来才能经由后者唤起为数十多个的Reflect APIs。
下面我们来看下Class类的源码片段
public final class Class<T> implements java.io.Serializable, java.lang.reflect.GenericDeclaration, java.lang.reflect.Type, java.lang.reflect.AnnotatedElement { private Class() {} public String toString() { return ( isInterface() ? "interface " : (isPrimitive() ? "" : "class ")) + getName(); }
注意:Class类的构造方法是private的,意指不允许任何人经由编程方式产生Class object。是的,其object只能由JVM产生。
"Class" object的取得途径
Java允许我们从多种管道为一个class生成对应的Class object。
Class object 诞生管道 | 示例 |
运用 getClass() 注:每个class 都有此函数 |
String str = "abc"; Class c1 = str.getClass(); |
运用 Class.getSuperclass() |
Button b = new Button(); Class c1 = b.getClass(); Class c2 = c1.getSuperclass(); |
运用 static method (最常被使用) |
Class c1 = Class.forName ("java.lang.String"); Class c2 = Class.forName ("java.awt.Button"); Class c3 = Class.forName ("java.util.LinkedList$Entry"); Class c4 = Class.forName ("I"); Class c5 = Class.forName ("[I"); |
运用 .class 语法 |
Class c1 = String.class; Class c2 = java.awt.Button.class; Class c3 = Main.InnerClass.class; Class c4 = int.class; Class c5 = int[].class; |
运用 primitive wrapper classes 的TYPE 语法 |
Class c1 = Boolean.TYPE; Class c2 = Byte.TYPE; Class c3 = Character.TYPE; Class c4 = Short.TYPE; Class c5 = Integer.TYPE; Class c6 = Long.TYPE; Class c7 = Float.TYPE; Class c8 = Double.TYPE; Class c9 = Void.TYPE; |
Java classes 组成分析
下面以java.util.LinkedList为例,将Java class的定义进行分块解析,每一块分别对应一个Reflect API.
LinkedList源码片段如下:
package java.util; //(1) import java.lang.*; //(2) public class LinkedList<E> //(3)(4)(5) extends AbstractSequentialList<E> //(6) implements List<E>, Queue<E>, Cloneable, java.io.Serializable //(7) { private static class Entry<E> { … }//(8) public LinkedList() { … } //(9) public LinkedList(Collection<? extends E> c) { … } public E getFirst() { … } //(10) public E getLast() { … } private transient Entry<E> header = …; //(11) private transient int size = 0; }
Java classes各成分所对应的Reflection APIs
上段代码的各个Java class成分,分别对应于下图的Reflect API,其中出现的Package、Method、Constructor、Field等classes,都定义与java.lang.reflect。
Java class 内部模块 | Java class 内部模块说明 |
相应之Reflection API |
返回值类型(return type) |
(1) package | class隶属哪个package | getPackage() | Package |
(2) import | class导入哪些classes | 无直接对应的API | |
(3) modifier |
class(或methods,fields) 的属性 |
int getModifiers() Modifier.toString(int) Modifier.isInterface(int) |
int String bool |
(4) class name or interface name |
class/interface | 名称getName() | String |
(5) type parameters |
参数化类型的名称 | getTypeParameters() |
TypeVariable <Class>[] |
(6) base class | base class(只可能一个) | getSuperClass() | Class |
(7) implemented | 实现有哪些interfaces | getInterfaces() | Class[] |
(8) inner classes | 内部classes | getDeclaredClasses() | Class[] |
(8') outer class |
如果我们观察的class本身是 inner classes,那么相对它 就会有个outer class。 |
getDeclaringClass() | Class |
(9) constructors |
构造函数 getDeclaredConstructors() |
不论public或private或其 它accesss level, 皆可获得。 |
Constructor[] |
(10) methods |
操作函数 getDeclaredMethods() |
不论public或private或其 它accesss level, 皆可获得。 |
Method[] |
(11) fields | 字段(成员变量) |
getDeclaredField(), 不论public或private 或其它access level, 皆可获得。 |
Field[] |
Java Reflection API 运用示例
下面给出上表中提到的每一个Reflection API,及其执行结果。
(1)找出class隶属的package
Class c = null; c = Class.forName(args[0]); Package p; p = c.getPackage(); if (p != null) System.out.println("package "+p.getName()+";"); 执行结果(例): package java.util;
(2)找出导入的classes
#001 ff = c.getDeclaredFields(); #002 for (int i = 0; i < ff.length; i++) #003 x = tName(ff[i].getType().getName(), classRef); #004 #005 cn = c.getDeclaredConstructors(); #006 for (int i = 0; i < cn.length; i++) { #007 Class cx[] = cn[i].getParameterTypes(); #008 for (int j = 0; j < cx.length; j++) #009 x = tName(cx[j].getName(), classRef); #010 } #011 #012 mm = c.getDeclaredMethods(); #013 for (int i = 0; i < mm.length; i++) { #014 x = tName(mm[i].getReturnType().getName(), classRef); #015 Class cx[] = mm[i].getParameterTypes(); #016 for (int j = 0; j < cx.length; j++) #017 x = tName(cx[j].getName(), classRef); #018 } #019 classRef.remove(c.getName()); //不必记录自己(不需import 自己) 执行结果(例): import java.util.ListIterator; import java.lang.Object; import java.util.LinkedList$Entry; import java.util.Collection; import java.io.ObjectOutputStream; import java.io.ObjectInputStream;
(3)找出class或interfece
#001 int mod = c.getModifiers(); #002 System.out.print(Modifier.toString(mod)); //整个modifier #003 #004 if (Modifier.isInterface(mod)) #005 System.out.print(" "); //关键词 "interface" 已含于modifier #006 else #007 System.out.print(" class "); //关键词 "class" #008 System.out.print(tName(c.getName(), null)); //class 名称 执行结果(例): public class LinkedList
(4)找出parameterized types 的名称
#001 TypeVariable<Class>[] tv; #002 tv = c.getTypeParameters(); //warning: unchecked conversion #003 for (int i = 0; i < tv.length; i++) { #004 x = tName(tv[i].getName(), null); //例如 E,K,V... #005 if (i == 0) //第一个 #006 System.out.print("<" + x); #007 else //非第一个 #008 System.out.print("," + x); #009 if (i == tv.length-1) //最后一个 #010 System.out.println(">"); #011 } 执行结果(例): public abstract interface Map<K,V> 或public class LinkedList<E>
(5)找出base class
#001 Class supClass; #002 supClass = c.getSuperclass(); #003 if (supClass != null) //如果有super class #004 System.out.print(" extends" + #005 tName(supClass.getName(),classRef)); 执行结果(例): public class LinkedList<E> extends AbstractSequentialList,
(6)找出implemented interfaces
#001 Class cc[]; #002 Class ctmp; #003 //找出所有被实现的interfaces #004 cc = c.getInterfaces(); #005 if (cc.length != 0) #006 System.out.print(", /r/n" + " implements "); //关键词 #007 for (Class cite : cc) //JDK1.5 新式循环写法 #008 System.out.print(tName(cite.getName(), null)+", "); 执行结果(例): public class LinkedList<E> extends AbstractSequentialList, implements List, Queue, Cloneable, Serializable,
(7)找出inner classes 和outer class
#001 cc = c.getDeclaredClasses(); //找出inner classes #002 for (Class cite : cc) #003 System.out.println(tName(cite.getName(), null)); #004 #005 ctmp = c.getDeclaringClass(); //找出outer classes #006 if (ctmp != null) #007 System.out.println(ctmp.getName()); 执行结果(例): LinkedList$Entry LinkedList$ListItr
(8a)找出所有constructors
#001 Constructor cn[]; #002 cn = c.getDeclaredConstructors(); #003 for (int i = 0; i < cn.length; i++) { #004 int md = cn[i].getModifiers(); #005 System.out.print(" " + Modifier.toString(md) + " " + #006 cn[i].getName()); #007 Class cx[] = cn[i].getParameterTypes(); #008 System.out.print("("); #009 for (int j = 0; j < cx.length; j++) { #010 System.out.print(tName(cx[j].getName(), null)); #011 if (j < (cx.length - 1)) System.out.print(", "); #012 } #013 System.out.print(")"); #014 } 执行结果(例): public java.util.LinkedList(Collection) public java.util.LinkedList()
(8b)找出所有constructors
#004 System.out.println(cn[i].toGenericString()); 执行结果(例): public java.util.LinkedList(java.util.Collection<? extends E>) public java.util.LinkedList()
(9a)找出所有methods
#001 Method mm[]; #002 mm = c.getDeclaredMethods(); #003 for (int i = 0; i < mm.length; i++) { #004 int md = mm[i].getModifiers(); #005 System.out.print(" "+Modifier.toString(md)+" "+ #006 tName(mm[i].getReturnType().getName(), null)+" "+ #007 mm[i].getName()); #008 Class cx[] = mm[i].getParameterTypes(); #009 System.out.print("("); #010 for (int j = 0; j < cx.length; j++) { #011 System.out.print(tName(cx[j].getName(), null)); #012 if (j < (cx.length - 1)) System.out.print(", "); #013 } #014 System.out.print(")"); #015 } 执行结果(例): public Object get(int) public int size()
(9b)找出所有methods
#004 System.out.println(mm[i].toGenericString()); public E java.util.LinkedList.get(int) public int java.util.LinkedList.size()
(10a)找出所有fields
#001 Field ff[]; #002 ff = c.getDeclaredFields(); #003 for (int i = 0; i < ff.length; i++) { #004 int md = ff[i].getModifiers(); #005 System.out.println(" "+Modifier.toString(md)+" "+ #006 tName(ff[i].getType().getName(), null) +" "+ #007 ff[i].getName()+";"); #008 } 执行结果(例): private transient LinkedList$Entry header; private transient int size;
(10b)找出所有fields
#004 System.out.println("G: " + ff[i].toGenericString()); private transient java.util.LinkedList.java.util.LinkedList$Entry<E> ?? java.util.LinkedList.header private transient int java.util.LinkedList.size
运行时生成instances
欲生成对象实体,在Reflection 动态机制中有两种作法,一个针对“无自变量ctor”,
一个针对“带参数ctor”。图6是面对“无自变量ctor”的例子。如果欲调用的是“带参数ctor“就比较麻烦些,图7是个例子,其中不再调用Class的newInstance(),而是调用Constructor 的newInstance()。代码(1)首先准备一个Class[]做为ctor的参数类型(本例指定为一个double和一个int),然后以此为自变量调用getConstructor(),获得一个专属ctor。接下来再准备一个Object[] 做为ctor实参值(本例指定3.14159和125),调用上述专属ctor的newInstance()。
(1)动态生成“Class object 所对应之class”的对象实体;无自变量。
#001 Class c = Class.forName("DynTest"); #002 Object obj = null; #003 obj = c.newInstance(); //不带自变量 #004 System.out.println(obj);
(2)动态生成“Class object 对应之class”的对象实体;自变量以Object[]表示。
#001 Class c = Class.forName("DynTest"); #002 Class[] pTypes = new Class[] { double.class, int.class }; #003 Constructor ctor = c.getConstructor(pTypes); #004 //指定parameter list,便可获得特定之ctor #005 #006 Object obj = null; #007 Object[] arg = new Object[] {3.14159, 125}; //自变量 #008 obj = ctor.newInstance(arg); #009 System.out.println(obj);
运行时调用methods
这个动作和上述调用“带参数之ctor”相当类似。首先准备一个Class[]做为ctor的参数类型(本例指定其中一个是String,另一个是Hashtable),然后以此为自变量调用getMethod(),获得特定的Method object。接下来准备一个Object[]放置自变量,然后调用上述所得之特定Method object的invoke(),如下面代码。知道为什么索取Method object时不需指定回返类型吗?因为method overloading机制要求signature(署名式)必须唯一,而回返类型并非signature的一个成份。换句话说,只要指定了method名称和参数列,就一定指出了一个独一无二的method。
#001 public String func(String s, Hashtable ht) #002 { #003 …System.out.println("func invoked"); return s; #004 } #005 public static void main(String args[]) #006 { #007 Class c = Class.forName("Test"); #008 Class ptypes[] = new Class[2]; #009 ptypes[0] = Class.forName("java.lang.String"); #010 ptypes[1] = Class.forName("java.util.Hashtable"); #011 Method m = c.getMethod("func",ptypes); #012 Test obj = new Test(); #013 Object args[] = new Object[2]; #014 arg[0] = new String("Hello,world"); #015 arg[1] = null; #016 Object r = m.invoke(obj, arg); #017 Integer rval = (String)r; #018 System.out.println(rval); #019 }
运行时变更fields内容
与先前两个动作相比,“变更field内容”轻松多了,因为它不需要参数和自变量。首先调用Class的getField()并指定field名称。获得特定的Field object之后便可直接调用Field的get()和set(),如下代码。
#001 public class Test { #002 public double d; #003 #004 public static void main(String args[]) #005 { #006 Class c = Class.forName("Test"); #007 Field f = c.getField("d"); //指定field 名称 #008 Test obj = new Test(); #009 System.out.println("d= " + (Double)f.get(obj)); #010 f.set(obj, 12.34); #011 System.out.println("d= " + obj.d); #012 } #013 }
参考文档: