`
yuanlanjun
  • 浏览: 1186273 次
文章分类
社区版块
存档分类
最新评论

浅谈Java反射机制(一)

 
阅读更多
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();
	}
	
}
先运行服务端,再运行客户端,这小小的测试,也算完成了。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics