题外话:
下个周末世界杯就开始了,对于一个地道的球迷而言,这无疑是一个期盼以久的盛大的节日,无论从生理上还是心理上我都做好了充分的准备,准备全身心的投入到这个四年一度的节日中去,祝天下球迷朋友们节日快乐,好好享受吧!
什么是反射机制
正像物理中的反射一样,就像我们站在镜子面前能看到自己的模样。但是这里的反射机制又有别于物理中的反射,这里的反射机制着重强调的是“动态的”。反射机制是指能在class(自己)运行的情况下,看到自己主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。由于设计的时候加入了这种机制使得java语言具有了一定的动态能力(所谓一定的动态能力是指:java语言并不能象python,ruby那样在程序运行时,允许改变程序结构和变量的类型,但是他可以在程序运行的时候检测自己的状态和行为,并能修改字段的值)。正是由于反射机制的存在,所以java语言又有别于“硬编码”的c,c++,同时也正是这个机制的优势,使得微软在后来模仿java语言发明了c#语言,同样c#语言也具备了这个优势。
如何实现:
java里面所有对象都继承于一个基本对象class object,这个对象不是我们通过程序手动写出来的,他是在每一个class使用的时候由jvm自动生成的。这个类提供了若干个Reflection API,我们可以调用这些Reflection API来检查class的相关方法,变量,名字,接口以及继承…………相关信息。而我们通过SUN提供的这些Reflection API来检查各种各样的class信息的过程就是反射(下面我写的这个例子就是做的这件事),象这种事,每天JVM都在做,任何一个时候都在不停的做,只要有一个class生成,被操作,jvm都会调用反射API去得到他的方法,属性,变量。罗列几个常用的API有:getName() 得到class/interface 名称;getDeclaredMethods() 得到方法;getDeclaredFields() 得到变量……。
例子(三个例子,得到字段,方法,名字):
以下是我使用反射机制的三个例子,分别是得到名字,方法,以及属性和修改属性。
例子一:
/*得到方法名字*/
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;
该例子摘自 侯捷 老师一书《java反射机制》“Java Reflection API 運用示例”一节,正像我们常常问的那样,我们在EJB里面写了个方法,或者引入了一个包,客户端怎么知道是哪一个包,是哪一个方法,就像上面一样,JVM其实在背后做了上面这段代码的事,然后打印了上面这个结果,也就是说JVM通过反射知道了他想知道的信息。明白了吧,JVM就是这样得到了这些信息。刚开始我学习反射的时候,有一个疑问在我脑海里困惑了很久“反射只能动态的时候看自己的方法,函数,变量,又不能象动态语言那样操作,这样做意义何在,似乎找不到一点好处”,通过这里,我明白了,其实反射不是给你看的,是给JVM看的,让他或者容器(例如EJB)知道到底该得到什么方法,什么class。
例子二:
/*得到所有方法*/
package src;
import java.lang.reflect.*;
public class reflectiontest {
public static void main(String args[]) {
try {
Class c = Class.forName("java.lang.String");//转化为class object对象,可以反射。
Method m[] = c.getDeclaredMethods();
System.out.println(m[0].toString());
/****查看自己的所有方法******/
for (int i = 0; i < m.length; i++)
System.out.println(m[i].toString());
/****************************/
/****查看自己的第一个方法****/
System.out.println(m[0].toString());
/****************************/
}
catch (Throwable e) {
System.err.println(e);
}
}
}
由于java是完全面相对象的编程,所以在java里面string型,int型,这些常量类型也是对象化了的,我们可以把他们当作一个对象来看待和操作。通过上面的例子得到的结果是所有string的公共方法。
例子三:
/*得到属性以及修改属性,也就是我们常常使用的set和get方法*/
public class Test {
public double d;
public static void main(String args[])
{
Class c = Class.forName("Test");
Field f = c.getField("d"); //指定field 名稱
Test obj = new Test();
System.out.println("d= " + (Double)f.get(obj));
f.set(obj, 12.34);
System.out.println("d= " + obj.d);
}
}
该例子摘自 侯捷 老师一书《java反射机制》倒数第二小节“執行期變更fields 內容”,这个方法大家用得多了吧,其实里面也包含了反射机制得原理,即使说我们通过实名把我们要操作的对象转换成class object对象Class c = Class.forName("Test");然后通过c.getField()方法(该方法就是反射制的体现) 就可以动态(这里所谓的动态就是指在程序在运行的时候)取得自己的变量,并且修改和设置。
为什么用reflection,他有什么好处:
其实JNDI就是reflection的一个具体表现。举个例:ejb里面我们放了一个类,客户端怎么知道我们要使用什么类的什么方法,我们知道用的是jndi,其实JNDI就是反射机制的一个具体表现,Class c = Class.forName("java.lang.String");双音号里面是调用的函数或者方法的名字,通过名字来找到我们要调用的方法,这就是我们说的JNDI,JVM在内部实例化了一个class object,正如我们上面提到的这个class object里面有很多方法,通过这些方法就可以看到他得到的那个类的所有的公用方法,并且调用相应的方法。否则客户端也不能知道我们调用的是什么类。
同样我们常常使用getXXX()和setXXX()方法也是一样的道理。
总结起来可以概括为:“动态的来选择执行的方法和变量,不是静态的写出来。”