Reflection,
这个字的意思是
“
反射、映象、倒影
”
,用在
Java
身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的
classes
。换句话说,
Java
程序可以加载一个运行时才得知名称的
class
,获悉其完整构造(
但不包括
methods
定义
),并生成其对象实体、或对其
fields
设值、或唤起其
methods
。 --来自百度百科定义
马上就要开始跟项目了,为了作些准备,了解了一下反射技术,今天想就自己对反射机制的了解作一些总结。
首先学习的是比较浅显的,通过传进来的对象去初始化一些变量,而这些变量是组成一个方法的必要条件,通过这些条件来调用指定的方法。界定一个唯一方法的因素有:
1,方法所属的类;
2,方法的名字;
3,方法的参数列表和顺序;
满足这三个条件,我们就可以通过java.lang.reflect.Method类,去创建一个Method类的对象method,通过method.invoke(affectedObject,params)来执行一个方法。
假定,我们现在是做远程的socket,通过流来传对象,对象皆为封装对象,即封装了需要用到的属性,类名、方法名、参数类型列表,参数列表:
package com.insigma.model;
import java.io.Serializable;
public class Call implements Serializable{
private String className;
private String methodName;
private Class[] paramTypes;
private Object[] params;
private Object result;
public Call(){
}
public Call(String className, String methodName,Class[] paramTypes, Object[] params){
this.className = className;
this.methodName = methodName;
this.paramTypes = paramTypes;
this.params = params;
}
public String getClassName(){
return className;
}
public String getMethodName(){
return methodName;
}
public Class[] getParamTypes(){
return paramTypes;
}
public Object[] getParams(){
return params;
}
public Object getResult(){
return result;
}
public void setResult(Object result){
this.result = result;
}
}
因为要通过流来传输对象,最好把这对象实现可序列化接口Serializable。通过构造器来为封装的属性赋值。
接下来就是ServerSocket,在这里监听远程socket那边是否有对象传过来,以作反应:
package com.insigma.model;
import java.io.*;
import java.net.*;
import java.util.*;
import java.lang.reflect.*;
public class SimpleServer {
private Map remoteObjects=new HashMap();
//存放远程对象的缓存
/** 把一个远程对象放到缓存中 */
public void register(String className,Object remoteObject){
remoteObjects.put( className,remoteObject);
}
public void service()throws Exception{
ServerSocket serverSocket = new ServerSocket(8000);
System.out.println("服务器启动.");
while(true){
Socket socket=serverSocket.accept();
InputStream in=socket.getInputStream();
ObjectInputStream ois=new ObjectInputStream(in);
OutputStream out=socket.getOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(out);
Call call=(Call)ois.readObject();
//接收客户发送的Call对象
System.out.println(call);
call=invoke(call);
//调用相关对象的方法
oos.writeObject(call);
//向客户发送包含了执行结果的Call对象
ois.close();oos.close();
socket.close();
}
}
public Call invoke(Call call){
Object result=null;
try{
String className=call.getClassName();
String methodName=call.getMethodName();
Object[] params=call.getParams();
Class classType=Class.forName(className);
Class[] paramTypes=call.getParamTypes();
Method method=classType.getMethod(methodName, paramTypes);
Object remoteObject=remoteObjects.get(className);
//从缓存中取出相关的远程对象
if(remoteObject==null){
throw new Exception(className+"的远程对象不存在");
}else{
result=method.invoke(remoteObject,params);
}
}catch(Exception e){
result=e;
}
call.setResult(result);
//设置方法执行结果
return call;
}
public static void main(String args[])throws Exception {
SimpleServer server=new SimpleServer();
//把事先创建的HelloServiceImpl对象加入到服务器的缓存中
server.register("com.insigma.model.HelloService",new HelloServiceImpl());
server.service();
}
}
这里,需要注册类型,没有注册的类型,远程传过来的时候,会出现异常,这里大概是出于安全考虑。
下来就是Socket的客户端了
package com.insigma.model;
import java.io.*;
import java.net.*;
public class SimpleClient {
public void invoke()throws Exception{
Socket socket = new Socket("localhost",8000);
OutputStream out=socket.getOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(out);
InputStream in=socket.getInputStream();
ObjectInputStream ois=new ObjectInputStream(in);
Call call=new Call("com.insigma.model.HelloService","getTime",new Class[]{},new Object[]{});
//Call call=new Call("com.insigma.model.HelloService","echo",new Class[]{String.class},new Object[]{"Hello"});
oos.writeObject(call);
//向服务器发送Call对象
call=(Call)ois.readObject();
//接收包含了方法执行结果的Call对象
System.out.println(call.getResult());
ois.close();
oos.close();
socket.close();
}
public static void main(String args[])throws Exception {
new SimpleClient().invoke();
}
}
当然咯,被反射的类也是必须贴上,不然给出一份不能运行的代码,肯定要被唾液淹死。对被反射的类,做了一个接口来解耦。
package com.insigma.model;
public interface HelloService {
public String echo(String words);
public String getTime();
}
这里是实现类,只提供很简单的测试功能。
package com.insigma.model;
import java.util.Date;
public class HelloServiceImpl implements HelloService{
@Override
public String echo(String words) {
return "echo:" + words;
}
@Override
public String getTime() {
return new Date().toString();
}
}
先运行服务端,再运行客户端,这小小的测试,也算完成了。