java 反射机制

JAVA有着一个非常突出的动态相关机制:Reflection,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。

当一个class被加载,或当加载器(class loader)的defineClass()被JVM调用,JVM 便自动产生一个Class 对象。

注意它的private Class() {},意指不允许任何人经由编程方式产生Class object。是的,其object 只能由JVM 产生。

Java允许我们从多种管道为一个class生成对应的Class object。图2是一份整理。

Class object 诞生管道

示例:

1)运用getClass()

注:每个class 都有此函数

String str = “abc”;

Class c1 = str.getClass();

2)运用Class.getSuperclass()

Button b = new Button();

Class c1 = b.getClass();

Class c2 = c1.getSuperclass();

3)运用static method——Class.forName()(最常被使用)

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 (“.class”);

4)运用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;


forName(“ss.bb.bean”)
JVM会在classapth中去找对应的类,设定在classpath的类,在java启动的时候最先被加载,并将Class对象保存起来,这样forName创建对象时就不需要通过classloader再去读取该类的文件了。而new 一个对象,一般不需要该类在classpath中设定,但可能需要通过classlaoder来加载。
当你确定此时内存中没有这个对象的时候,你就可以用class.forName();来创建一个对象,而假如new是不管你内存中是否有这个对象都会创建一个新的对象,也是说会在内存中开辟一个新的内存空间


最近在成都写一个移动增值项目,俺负责后台 server 端。功能很简单,手机用户通过 GPRS

打开 Socket 与服务器连接,我则根据用户传过来的 数据做出响应。做过类似项目的兄弟一

定都知道,首先需要定义一个类似于 MSNP 的通讯协议,不过今天的话题是如何把这个系

统设计得具有高度的扩展性。由于 这个项目本身没有进行过较为完善的客户沟通和需求分

析,所以以后肯定会有很多功能上的扩展,通讯协议肯定会越来越庞大,而我作为一个不那

么勤快的人,当然 不想以后再去修改写好的程序,所以这个项目是实践面向对象设计的好

机会。

//首先定义一个接口来隔离类:
public interface Operator
{
//    public java.util.List act(java.util.List params);
public java.util.List act(String content,String content2,java.util.List params);
} 

根据设计模式的原理,我们可以为不同的功能编写不同的类,每个类都继承Operator接口,客户端只需要针对Operator接口编程就可以避免很多麻烦。比如这个类:

import java.util.*;
public class Success implements Operator
{
public static void main(String[] args) {
List list = new ArrayList();
list.add("Success3");
Operator op = new Success();
System.out.println("act===" + op.act("Success1", "Success2", list));
}
//       public java.util.List act(java.util.List params)
public java.util.List act(String content, String content2,
java.util.List params) {
List result = new ArrayList();
result.add(content);
result.add(content2);
result.add(params);
return result;
}
} 

同样,也可以写另一个类:

import java.util.*;
public class Load implements Operator
{
public static void main(String[] args) {
List list = new ArrayList();
list.add("Load3");
Operator op = new Load();
System.out.println("act===" + op.act("Load1", "Load2", list));
}
//       public java.util.List act(java.util.List params)
public java.util.List act(String content, String content2,
java.util.List params)
{
List result = new ArrayList();
result.add(content);
result.add(content2);
result.add(params);
return result;
}
}

我们还可以写其他很多类,但是有个问题,接口是无法实例化的,我们必须手动控制具体实例化哪个类,这很不爽,如果能够向应用程序传递一个参数,让自己去选择实例化一个类,执行它的act方法,那我们的工作就轻松多了。

很幸运,我使用的是Java,只有Java才提供这样的反射机制,或者说内省机制,可以实现我们的无理要求。编写一个配置文件emp.properties:

成功响应

1000=Success

向客户发送普通文本消息

2000=Load

客户向服务器发送普通文本消息

3000=Store

文件中的键名是客户将发给我的消息头,客户发送1000给我,那么,我就执行Success类的act方法,类似的如果发送2000给我,那就执行Load类的act方法,这样一来系统就完全符合开闭原则了,如果要添加新的功能,完全不需要修改已有代码,只需要在配置文件中添加对应规则,然后编写新的类,实现act方法就ok,即使我弃这个项目而去,它将来也可以很好的扩展。这样的系统具备了非常良好的扩展性和可插入性。

下面这个例子体现了动态加载的功能,程序在执行过程中才知道应该实例化哪个类:

import java.lang.reflect.*;
import java.util.Properties;
import java.io.FileInputStream;
import java.util.List;
//这个程序是针对Operator编程的,所以无需做任何修改,直接提供Load和Store类,

就可以支持20003000做参数的调用
//有了这样的内省机制,可以把接口的作用发挥到极至,设计模式也更能体现出威力,

而不仅仅供我们饭后闲聊。
public class TestReflect
{
//加载配置文件,查询消息头对应的类名
private String loadProtocal(String header)
{
String result=null;
try
{
Properties prop=new Properties();
//           FileInputStream fis=new FileInputStream("emp.properties");
//           id = prop.getProperty(idString);
//           prop.load(fis);
//           fis.close();
prop.load(getTCL().getResourceAsStream("emp.properties"));
result=prop.getProperty(header);
}catch(Exception e)
{
System.out.println(e);
}
return result;
}
private static ClassLoader getTCL() throws IllegalAccessException,
InvocationTargetException {
Method method = null;
try {
method = Thread.class.getMethod("getContextClassLoader", null);
} catch (NoSuchMethodException e) {
return null;
}
return (ClassLoader)method.invoke(Thread.currentThread(), null);
}

//针对消息作出响应,利用反射导入对应的类
public String response(String header,String content,String content2,List list)
{
String result=null;
String s=null;
try
{
/*
* 导入属性文件emp.properties,查询header所对应的类的名字
* 通过反射机制动态加载匹配的类,所有的类都被Operator接口隔离
* 可以通过修改属性文件、添加新的类(继承MsgOperator接口)来扩展协议
*/
s="org.bromon.reflect."+this.loadProtocal(header).trim();
//加载类
System.out.println("s==="+s);//打印 s===org.bromon.reflect.Success
Class c=Class.forName(s);
//java.lang.reflect.Methods 是用来描述某个类中单个方法的一个类
//           Method m[] = c.getDeclaredMethods();//
//           for (int i = 0; i < m.length; i++)//
//               System.out.println(m[i].toString());
//  打印   public java.util.List org.bromon.reflect.Success.act(java.util.List)
//创建类的事例
Operator mo=(Operator)c.newInstance();
System.out.println("mo==="+mo);
//构造参数列表
Class params[]=new Class[3];
//           params[0]=Class.forName("java.util.List");
params[0]=Class.forName("java.lang.String");
params[1]=Class.forName("java.lang.String");
params[2]=Class.forName("java.util.List");
System.out.println("params[0]==="+params[0]);
//           //查询act方法
Method m=c.getMethod("act",params);
System.out.println("method=="+m.toString());
Object[] args=new Object[3];
args[0]=content;
args[1]=content2;
args[2]=list;
//           //调用方法并且获得返回
Object returnObject=m.invoke(mo,args);//这个地方出问题了,抛异常~~~~
//           System.out.println("returnObject==="+returnObject);
List result2 = (List)returnObject;
result = (String)result2.get(0);
System.out.println("result2=="+result2);
//
}catch(Exception e)
{
System.out.println("Handler-response:"+e);

//Handler-response:java.lang.IllegalArgumentException: argument type mismatch
//IllegalArgumentException - 如果该方法是实例方法,且指定对象参数不是

声明基础方法的类或接口(或其中的子类或实现程序)的实例;
//如果实参和形参的数量不相同;如果基本参数的解包转换失败;

或者如果在解包后,无法通过方法调用转换将参数值转换为相应的形参类型。
}
return result;
}
public static void main(String args[])
{
TestReflect tr=new TestReflect();
List list = new java.util.ArrayList();
list.add("测试List");
tr.response("2000","Load1","Load2",list);//1000是Success,2000是Load
tr.response("1000","Success1","Success2",list);//1000是Success,2000是Load

}
}

测试一下,run一下TestReflect类,打印内容有,great!!

result2==[Load1, Load2, [测试List]]
result2==[Success1, Success2, [测试List]]

这个程序是针对Operator编程的,所以无需做任何修改,直接提供Load和Store类,就可以支持2000、3000做参数的调用。

有了这样的内省机制,可以把接口的作用发挥到极至,设计模式也更能体现出威力。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值