欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java反射机制浅析

程序员文章站 2022-05-13 11:12:37
...

什么是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都是用反射机制实现的。   

为什么要使用反射机制
这篇文章介绍的不错

引用
http://blog.csdn.net/sole_ghost/article/details/1561646


    文中从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 }

 

 参考文档:

http://blog.csdn.net/sole_ghost/article/details/1562094

 



 

相关标签: java reflect