现在的位置: 首页 > 综合 > 正文

java反射机制

2013年10月07日 ⁄ 综合 ⁄ 共 4891字 ⁄ 字号 评论关闭
 
 

我们先从一个类开始,现在随便写一个类
public class TestMain {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}}
首先,要明白什么是反射,你首先要明白java.lang.Class是什么
刚才那个文件TestMain是一个类,这个类保存在磁盘上的一个位置,名字叫做TestMain

。将其编译后,就生成一个TestMain.class的文件。
对于每个类而言,JRE都为其保留一个不变的Class 类型的对象。一个Class 对象包含

了特定某个类的有关信息。你可以通过调用Class 对象的有关方法,返回特定类的构造

器对象,方法对象和数据成员对象
先不用急着理解什么是Class,我们先取一个Class,以后慢慢再从实用中理解
取得一个Class类的方法有很多,最常用的有2种:
1、一种是用类名+.class取得。例如上面的TestMain类: Class clazz =

TestMain.class;等效与class.forName("clazz")
.class也可用在简单数据类型上,如int.class
2、另外一种是用对象的getClass方法:例如:  TestMain tm = new TestMain

();  Class clazz = tm.getClass();

这里提2种高级获取Class类的方法,这2个方法对大多数人来说,可能不会用到。
 第一种:读取一个class文件,可以得到一个byte[]数组,这个数组可以用

ClassLoader    类的defineClass方法,生成一个类。   

第二种:这个方法是动态代理用到的,用法是:    import

sun.misc.ProxyGenerator;    ...    

byte[] b = ProxyGenerator.generateProxyClass("proxy0", new Class[]{interf}) 

然后用返回得到的byte数组产生一个类。其中参数interf是一个接口。
其次说明一下Class.forName()这个方法,这个方法涉及到ClassLoader机制的原因,不

在这里讲了,讲起来比较复杂
Class.forName:你简单理解为用当前ClassLoader的find方法去找某个类。
首先要明白的就是在java中所有的类都会被表示成java.lang.Class类的实例,别

和.class文件弄混了,也别和类的概念弄混了
现在我们要开始用反射的机制对刚才那个类进行操作了。在我讲的过程中,大家先思考

一个问题:为什么要用反射调用刚才那个方法。
第一步,我们得到了一个Class对象:Class clazz = TestMain.class;
第二步,我们获取这个类的所有方法:
Method[] methods = clazz.getMethods();//java.lang.reflect.Method
第三步,我们要开始调用这些方法中的某一个了
import java.lang.reflect.*;
public class ReflectTest
{
public static void main(String[] args) {
Class clazz = TestMain.class;
Method[] methods = clazz.getMethods();
for(int i=0; i<methods.length; i++) {
String methodName = methods[i].getName();
System.out.println(methodName);
} } }

public class ReflectTest
    {
 
 public static void main(String args[]) throws Exception
     {
  Class clazz = TestMain.class;
  Method[] methods = clazz.getDeclaredMethods();
  for (int i = 0; i < methods.length; i++)
      {
   String methodName = methods[i].getName();
   System.out.println(methodName);
   
      }
  String[] param = new String[1];
  param[0] = "my name";
  Method m = clazz.getMethod("setName", new Class[] {

java.lang.String.class });
  // 调用setName方法
  Object o = clazz.newInstance();
  m.invoke(o, param);
  // 调用getName方法
  m = clazz.getMethod("getName", null);
  Object result = m.invoke(o);
  System.out.println("result = " + result);
     }
    }

public class TestMain
    {
 private String name;

 public String getName()
     {
  return name;
     }

 public void setName(String name)
     {
  this.name = name;
     }
 
   
    }
最后那段代码:m.invoke(o, param);是调用你的method
反射机制在你所做的java应用中无所不在大家都在jsp中用过javaBean吧其实,刚才这

段代码我们再封装一次,就是javaBean的机制了.
javaBean的机制是这样的:
第一, 一个类有一个空的构造子
第二, 为这个类的所有私有成员提供了get和set方法(或其中之一)
私有成员和get,set方法遵循命名规则。即成员名第一个字母小写,get,set方法后面

带的私有成员名的第一个字母大写
为什么要有一个空的构造子?因为要用clazz.newInstance();生成这个对象

public class OneBean {
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}}
现在要修改刚才这个试验了。这个的试验目的是:在不改变代码的情况下,调用配置的

方法为了方便,这里不用xml,但原理是一样的
好了,代码改好了:
public static void main(String args[]) throws Exception
     {
  String className = System.getProperty("className");
  System.out.println("className = " + className);
  Class clazz = Class.forName(className);
  String[] param;
  String temp = System.getProperty("sname");
  if (temp == null)
      param = null;
  else
      param = new String[] { temp };
  String methodName = System.getProperty("methodName");
  Method m = null;
  if (temp == null)
      m = clazz.getMethod(methodName, null);
  else
      m = clazz.getMethod(methodName, new Class[] {

java.lang.String.class });
  // 调用方法
  Object o = clazz.newInstance();
  m.invoke(o, param);
  
     }
 
这里的原理是从配置文件中指定需要调用那些函数和方法,并知名其参数。首先,设

置环境变量,设置的方法大家应该知道吧,就是指定java虚拟机的参数,-Dkey=value
这里key我设置为如下: 两块石头(69707208) 22:38:35 这里key我设置为如下: -

Dzz.test.className=zz.test.TestMain -Dzz.test.name="my name" -

Dzz.test.methodName="setN  大家一起乐(125197462) 22:38:41 这样容易让大家都用

系统属性吧,我觉得还是用一个单独的属性类比较好  两块石头(69707208) 22:38:51

-Dzz.test.className=zz.test.TestMain -Dzz.test.name="my name" -

Dzz.test.methodName="setName"   两块石头(69707208) 22:39:16 无论用什么,其实

目的只有一个,就是能方便的获取到

环境变量取起来相对方便,如果配置内容很少的话,建议还是用环境变量来做。  首先

设置环境变量,这一步在你的ide环境中怎么做,大家知道吧
如果有不知道的,现在赶快说出来,我看看有没有必要再教这个。 
用eclipse的,在你运行的这个类上点右键,选run as->run,然后在上面的tab上选

argument,在VM arguments里输入下面这样的内容: -

Dzz.test.className=zz.test.TestMain -Dzz.test.name="my name" -

Dzz.test.methodName="setN
-Dzz.test.className=zz.test.TestMain -Dzz.test.name="my name" -

Dzz.test.methodName="setName"
这部分不属于反射的内容,只是顺便提一下
刚才那段代码,我解释一下
String className = System.getProperty("zz.test.className"); 这个就是取刚刚在
环境变量里配置的值的内容

Class clazz = Class.forName(className);
这个是寻找你配置的那个类。取得其Class对象
其实,看到这里,大家应该明白一些了,反射最主要的目的,就是跟配置挂钩,做配置
要求的内容。如果配的合适,可以做很多复杂和有用的事情。
例如,现在那个Bean不是你写的,而是客户的,你就不可能直接去调。而是需要客户自
己去装配这也就是为什么j2ee有了部署员的原因。因为很多东西需要装配在一起才能起作用。刚才那个用环境变量来改变程序的方式,你也可以看作是注入。
aop框架则稍微复杂一些,你可以简单的理解为在反射之外,提供了一些其他事情。
aop框架说起来比较复杂,这里不说了,有兴趣,一会我们再讨论
环境变量除了类名,其他可以不用改

下面我们总结一下:其实反射的机制内容非常多,我这里只说了一下如何找Class类和如何调用方法。  机制是java平台下各种框架实现的核心技术任何一个框架,struts,hibernate,spring等,以及应用服务器,例如tomcat,

weblogic,等都大量用了反射机制及思想  其目的就是能够把我们写的程序纳入到容器中运行。
反射有一个复杂的衍生体叫做动态代理  反射也是你要掌握java的最基础功力。
没有这个功力,你学习其他框架及技术的时候都会觉得很吃力。
例如在web.xml中随时可以见到这样一句话: <servlet-class>classname</ servlet-
name>
以及参数<init-param>value</init-param>等,这些都是反射所需要的
我建议大家,如果要想把java学的上一个层次,首先好好查一查如何使用反射机制。这
样对你以后学习各种框架有很多好处。 

抱歉!评论已关闭.