- 浏览: 680370 次
- 性别:
- 来自: 杭州
文章分类
- 全部博客 (141)
- java (58)
- SQL (7)
- java开源 (2)
- javascript (3)
- struts2 (2)
- oracle (6)
- junit (1)
- js报表 (1)
- jQuery (5)
- 插件安装 (1)
- myeclipse (1)
- xfire (1)
- weblogic (1)
- hibernate (6)
- loading (1)
- jbpm (3)
- 物语 (0)
- android (14)
- spring (20)
- BigDecimal (1)
- view (1)
- 总结 (2)
- application (1)
- Netty (5)
- aop (1)
- redis (7)
- double (1)
- restful (1)
- cache (3)
- profile (1)
- redisTemplate (1)
- poi (3)
- excel导出 (1)
- mysql (7)
- group (4)
- replication (4)
- proxysql (1)
- windows (1)
- version (1)
- mongodb (2)
- RocketMQ (1)
- MQ (1)
- RSA (1)
- 日志 (2)
- ip (1)
- socket (1)
- hibernate-validator (1)
- delayQueue (1)
- spring-retry (1)
- rabbitmq (3)
- httpclient (1)
- tools (1)
- 增量发布 (1)
- web (3)
- spring-boot (5)
- druid (2)
- pageHelper (1)
- freemarker (1)
- RequestMapping (1)
- 性能优化 (2)
- springBoot (1)
- docker (2)
- 安全 (0)
- 国际化 (3)
- websocket (1)
- stomp (1)
- shiro (1)
- 网络安全 (2)
- 锁 (1)
- logback (1)
最新评论
-
changerzhuo_319:
谢谢大佬, 查了一天了没解决
Spring-boot构建多模块依赖工程时,maven打包异常:程序包xxx不存在 -
迪伦少校:
spring越来越优秀的同时,也越来越复杂
spring核心技术(1) -
hbxflihua:
ivi13 写道这种方式会有个问题,假如有个商户的交易量特别大 ...
使用spring-retry实现支付系统异步通知 -
ivi13:
这种方式会有个问题,假如有个商户的交易量特别大,通知全部失败, ...
使用spring-retry实现支付系统异步通知 -
ckxlnd:
挺好的 有借鉴意义
重写DispatcherServlet获取springmvc 所有RequestMapping的url
在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法?答案是肯定的。这种动态获取类的信息,以及动态调用对象的方法的功能来自于Java语言的反射(Reflection)机制。Java反射机制主要提供了以下功能:
◆在运行时判断任意一个对象所属的类;
◆在运行时构造任意一个类的对象;
◆在运行时判断任意一个类所具有的成员变量和方法;
◆在运行时调用任意一个对象的方法;
◆生成动态代理。
本章首先介绍了Java Reflection API的用法,然后介绍了一个远程方法调用的例子,在这个例子中客户端能够远程调用服务器端的一个对象的方法。服务器端采用了反射机制提供的动态调用方法的功能,而客户端则采用了反射机制提供的动态代理功能。
10.1 Java Reflection API简介
在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中。
◆Class类:代表一个类。
◆Field类:代表类的成员变量(成员变量也称为类的属性)。
◆Method类:代表类的方法。
◆Constructor类:代表类的构造方法。
◆Array类:提供了动态创建数组,以及访问数组元素的静态方法。
如例程10-1所示DumpMethods类演示了Reflection API的基本作用,它读取命令行参数指定的类名,然后打印这个类所具有的方法信息:
例程10-1 DumpMethods.java
import java.lang.reflect.*;public class DumpMethods { public static void main(String args[]) throws Exception{ //加载并初始化命令行参数指定的类 Class classType = Class.forName(args[0]); //获得类的所有方法 Method methods[] = classType.getDeclaredMethods(); for(int i = 0; i < methods.length; i++) System.out.println(methods[i].toString()); }}
运行命令“java DumpMethods java.util.Stack”,就会显示java.util.Stack类所具有的方法,程序的打印结果如下:
public synchronized java.lang.Object java.util.Stack.pop()public java.lang.Object java.util.Stack.push(java.lang.Object)public boolean java.util.Stack.empty()public synchronized java.lang.Object java.util.Stack.peek()public synchronized int java.util.Stack.search(java.lang.Object)
如例程10-2所示ReflectTester类进一步演示了Reflection API的基本使用方法。ReflectTester类有一个copy(Object object)方法,这个方法能够创建一个和参数object同样类型的对象,然后把object对象中的所有属性复制到新建的对象中,并将它返回。
这个例子只能复制简单的JavaBean,假定JavaBean的每个属性都有public类型的getXXX()和setXXX()方法。
例程10-2 ReflectTester.java
import java.lang.reflect.*;public class ReflectTester { public Object copy(Object object) throws Exception{ //获得对象的类型 Class classType=object.getClass(); System.out.println("Class:"+classType.getName()); //通过默认构造方法创建一个新的对象 Object objectCopy=classType.getConstructor(new Class[]{}).newInstance(new Object[]{}); //获得对象的所有属性 Field fields[]=classType.getDeclaredFields(); for(int i=0; i Field field=fields[i]; String fieldName=field.getName(); String firstLetter=fieldName.substring(0,1).toUpperCase(); //获得和属性对应的getXXX()方法的名字 String getMethodName="get"+firstLetter+fieldName.substring(1); //获得和属性对应的setXXX()方法的名字 String setMethodName="set"+firstLetter+fieldName.substring(1); //获得和属性对应的getXXX()方法 Method getMethod=classType.getMethod(getMethodName,new Class[]{}); //获得和属性对应的setXXX()方法 Method setMethod=classType.getMethod(setMethodName,new Class[]{field.getType()}); //调用原对象的getXXX()方法 Object value=getMethod.invoke(object,new Object[]{}); System.out.println(fieldName+":"+value); //调用复制对象的setXXX()方法 etMethod.invoke(objectCopy,new Object[]{value}); } return objectCopy; } public static void main(String[] args) throws Exception{ Customer customer=new Customer("Tom",21); customer.setId(new Long(1)); Customer customerCopy=(Customer)new ReflectTester().copy(customer); System.out.println("Copy information:"+customerCopy.getName()+""+customerCopy.getAge()); }}class Customer{ //Customer类是一个JavaBean private Long id; private String name; private int age; public Customer(){} public Customer(String name,int age){ this.name=name; this.age=age; } public Long getId(){return id;} public void setId(Long id){this.id=id;} public String getName(){return name;} public void setName(String name){this.name=name;} public int getAge(){return age;} public void setAge(int age){this.age=age;}}
#p#
ReflectTester类的copy(Object object)方法依次执行以下步骤。
(1)获得对象的类型:
Class classType=object.getClass();System.out.println("Class:"+classType.getName());
在java.lang.Object类中定义了getClass()方法,因此对于任意一个Java对象,都可以通过此方法获得对象的类型。Class类是Reflection API中的核心类,它有以下方法。
◆getName():获得类的完整名字。
◆getFields():获得类的public类型的属性。
◆getDeclaredFields():获得类的所有属性。
◆getMethods():获得类的public类型的方法。
◆getDeclaredMethods():获得类的所有方法。
◆getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes参数指定方法的参数类型。
◆getConstrutors():获得类的public类型的构造方法。
◆getConstrutor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes参数指定构造方法的参数类型。
◆newInstance():通过类的不带参数的构造方法创建这个类的一个对象。
(2)通过默认构造方法创建一个新的对象:
Object objectCopy=classType.getConstructor(new Class[]{}).newInstance(new Object[]{});
以上代码先调用Class类的getConstructor()方法获得一个Constructor对象,它代表默认的构造方法,然后调用Constructor对象的newInstance()方法构造一个实例。
(3)获得对象的所有属性:
Field fields[]=classType.getDeclaredFields();
Class类的getDeclaredFields()方法返回类的所有属性,包括public、protected、默认和private访问级别的属性。
(4)获得每个属性相应的getXXX()和setXXX()方法,然后执行这些方法,把原来对象的属性复制到新的对象中:
for(int i=0; i Field field=fields[i]; String fieldName=field.getName(); String firstLetter=fieldName.substring(0,1).toUpperCase(); //获得和属性对应的getXXX()方法的名字 String getMethodName="get"+firstLetter+fieldName.substring(1); //获得和属性对应的setXXX()方法的名字 String setMethodName="set"+firstLetter+fieldName.substring(1); //获得和属性对应的getXXX()方法 Method getMethod=classType.getMethod(getMethodName,new Class[]{}); //获得和属性对应的setXXX()方法 Method setMethod=classType.getMethod(setMethodName,new Class[]{field.getType()}); //调用原对象的getXXX()方法 Object value=getMethod.invoke(object,new Object[]{}); System.out.println(fieldName+":"+value); //调用复制对象的setXXX()方法 setMethod.invoke(objectCopy,new Object[]{value});}
以上代码假定每个属性都有相应的getXXX()和setXXX()方法,并且在方法名中,“get”和“set”的后面一个字母为大写。例如,Customer类的name属性对应getName()和setName()方法。Method类的invoke(Object obj,Object args[])方法用于动态执行一个对象的特定方法,它的第一个obj参数指定具有该方法的对象,第二个args参数指定向该方法传递的参数。
如例程10-3所示的InvokeTester类的main()方法中,运用反射机制调用一个InvokeTester对象的add()和echo()方法。
例程10-3 InvokeTester.java
import java.lang.reflect.*;public class InvokeTester { public int add(int param1,int param2){ return param1+param2; } public String echo(String msg){ return "echo:"+msg; } public static void main(String[] args) throws Exception{ Class classType=InvokeTester.class; Object invokeTester=classType.newInstance(); //调用InvokeTester对象的add()方法 Method addMethod=classType.getMethod("add",new Class[]{int.class,int.class}); Object result=addMethod.invoke(invokeTester, new Object[]{new Integer(100),new Integer(200)}); System.out.println((Integer)result); //调用InvokeTester对象的echo()方法 Method echoMethod=classType.getMethod("echo",new Class[]{String.class}); result=echoMethod.invoke(invokeTester,new Object[]{"Hello"}); System.out.println((String)result); }}
add()方法的两个参数为int类型,获得表示add()方法的Method对象的代码如下:
Method addMethod=classType.getMethod("add",new Class[]{int.class,int.class});
Method类的invoke(Object obj,Object args[])方法接收的参数必须为对象,如果参数为基本类型数据,必须转换为相应的包装类型的对象。invoke()方法的返回值总是对象,如果实际被调用的方法的返回类型是基本类型数据,那么invoke()方法会把它转换为相应的包装类型的对象,再将其返回。
在本例中,尽管InvokeTester类的add()方法的两个参数及返回值都是int类型,调用addMethod对象的invoke()方法时,只能传递Integer类型的参数,并且invoke()方法的返回类型也是Integer类型,Integer类是int基本类型的包装类:
Object result=addMethod.invoke(invokeTester,new Object[]{new Integer(100),new Integer(200)});System.out.println((Integer)result); //result为Integer类型
java.lang.Array类提供了动态创建和访问数组元素的各种静态方法。如例程10-4所示的ArrayTester1类的main()方法创建了一个长度为10的字符串数组,接着把索引位置为5的元素设为“hello”,然后再读取索引位置为5的元素的值。
#p#
例程10-4 ArrayTester1.java
import java.lang.reflect.*;public class ArrayTester1 { public static void main(String args[])throws Exception { Class classType = Class.forName("java.lang.String"); //创建一个长度为10的字符串数组 Object array = Array.newInstance(classType, 10); //把索引位置为5的元素设为"hello" Array.set(array, 5, "hello"); //读取索引位置为5的元素的值 String s = (String) Array.get(array, 5); System.out.println(s); }}
如例程10-5所示的ArrayTester2类的main()方法创建了一个5×10×15的整型数组,并把索引位置为[3][5][10]的元素的值为设37。
例程10-5 ArrayTester2.java
import java.lang.reflect.*;public class ArrayTester2{ public static void main(String args[]) { int dims[] = new int[]{5, 10, 15}; Object array = Array.newInstance(Integer.TYPE, dims); //使arrayObj引用array[3] Object arrayObj = Array.get(array, 3); Class cls = arrayObj.getClass().getComponentType(); System.out.println(cls); //使arrayObj引用array[3][5] arrayObj = Array.get(arrayObj, 5); //把元素array[3][5][10]设为37 Array.setInt(arrayObj, 10, 37); int arrayCast[][][] = (int[][][]) array; System.out.println(arrayCast[3][5][10]); }}
10.2 在远程方法调用中运用反射机制
假定在SimpleServer服务器端创建了一个HelloServiceImpl对象,它具有getTime()和echo()方法。HelloServiceImpl类实现了HelloService接口。如例程10-6和例程10-7所示分别是HelloService接口和HelloServiceImpl类的源程序。
例程10-6 HelloService.java
package remotecall;import java.util.Date;public interface HelloService{ public String echo(String msg); public Date getTime();}
例程10-7 HelloServiceImpl.java
package remotecall;import java.util.Date;public class HelloServiceImpl implements HelloService{ public String echo(String msg){ return "echo:"+msg; } public Date getTime(){ return new Date(); }}
SimpleClient客户端如何调用服务器端的HelloServiceImpl对象的getTime()和echo()方法呢?显然,SimpleClient客户端需要把调用的方法名、方法参数类型、方法参数值,以及方法所属的类名或接口名发送给SimpleServer,SimpleServer再调用相关对象的方法,然后把方法的返回值发送给SimpleClient。
为了便于按照面向对象的方式来处理客户端与服务器端的通信,可以把它们发送的信息用Call类(如例程10-8所示)来表示。一个Call对象表示客户端发起的一个远程调用,它包括调用的类名或接口名、方法名、方法参数类型、方法参数值和方法执行结果。
例程10-8 Call.java
package remotecall;import java.io.*;public class Call implements Serializable{ private String className; //表示类名或接口名 private String methodName; //表示方法名 private Class[] paramTypes; //表示方法参数类型private Object[] params; //表示方法参数值//表示方法的执行结果//如果方法正常执行,则result为方法返回值,如果方法抛出异常,那么result为该异常。 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 void setClassName(String className){this.className=className;} public String getMethodName(){return methodName;} public void setMethodName(String methodName){this.methodName=methodName;} public Class[] getParamTypes(){return paramTypes;} public void setParamTypes(Class[] paramTypes){this.paramTypes=paramTypes;} public Object[] getParams(){return params;} public void setParams(Object[] params){this.params=params;} public Object getResult(){return result;} public void setResult(Object result){this.result=result;} public String toString(){ return "className="+className+" methodName="+methodName; }}
SimpleClient调用SimpleServer端的HelloServiceImpl对象的echo()方法的流程如下。
(1)SimpleClient创建一个Call对象,它包含了调用HelloService接口的echo()方法的信息。
(2)SimpleClient通过对象输出流把Call对象发送给SimpleServer。
(3)SimpleServer通过对象输入流读取Call对象,运用反射机制调用HelloServiceImpl对象的echo()方法,把echo()方法的执行结果保存到Call对象中。
(4)SimpleServer通过对象输出流把包含了方法执行结果的Call对象发送给SimpleClient。
(5)SimpleClient通过对象输入流读取Call对象,从中获得方法执行结果。
#p#
如例程10-9和例程10-10所示分别是SimpleServer和SimpleClient的源程序。
例程10-9 SimpleServer.java
package remotecall;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("remotecall.HelloService",new HelloServiceImpl()); server.service(); }}
例程10-10 SimpleClient.java
package remotecall;import java.io.*;import java.net.*;import java.util.*;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("remotecall.HelloService","getTime",new Class[]{},new Object[]{}); Call call=new Call("remotecall.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(); }}
先运行命令“java remotecall.SimpleServer”,再运行命令“java remotecall. SimpleClient”,SimpleClient端将打印“echo:Hello”。该打印结果是服务器端执行HelloServiceImpl对象的echo()方法的返回值。如图10-1所示显示了SimpleClient与SimpleServer的通信过程。
◆在运行时判断任意一个对象所属的类;
◆在运行时构造任意一个类的对象;
◆在运行时判断任意一个类所具有的成员变量和方法;
◆在运行时调用任意一个对象的方法;
◆生成动态代理。
本章首先介绍了Java Reflection API的用法,然后介绍了一个远程方法调用的例子,在这个例子中客户端能够远程调用服务器端的一个对象的方法。服务器端采用了反射机制提供的动态调用方法的功能,而客户端则采用了反射机制提供的动态代理功能。
10.1 Java Reflection API简介
在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中。
◆Class类:代表一个类。
◆Field类:代表类的成员变量(成员变量也称为类的属性)。
◆Method类:代表类的方法。
◆Constructor类:代表类的构造方法。
◆Array类:提供了动态创建数组,以及访问数组元素的静态方法。
如例程10-1所示DumpMethods类演示了Reflection API的基本作用,它读取命令行参数指定的类名,然后打印这个类所具有的方法信息:
例程10-1 DumpMethods.java
import java.lang.reflect.*;public class DumpMethods { public static void main(String args[]) throws Exception{ //加载并初始化命令行参数指定的类 Class classType = Class.forName(args[0]); //获得类的所有方法 Method methods[] = classType.getDeclaredMethods(); for(int i = 0; i < methods.length; i++) System.out.println(methods[i].toString()); }}
运行命令“java DumpMethods java.util.Stack”,就会显示java.util.Stack类所具有的方法,程序的打印结果如下:
public synchronized java.lang.Object java.util.Stack.pop()public java.lang.Object java.util.Stack.push(java.lang.Object)public boolean java.util.Stack.empty()public synchronized java.lang.Object java.util.Stack.peek()public synchronized int java.util.Stack.search(java.lang.Object)
如例程10-2所示ReflectTester类进一步演示了Reflection API的基本使用方法。ReflectTester类有一个copy(Object object)方法,这个方法能够创建一个和参数object同样类型的对象,然后把object对象中的所有属性复制到新建的对象中,并将它返回。
这个例子只能复制简单的JavaBean,假定JavaBean的每个属性都有public类型的getXXX()和setXXX()方法。
例程10-2 ReflectTester.java
import java.lang.reflect.*;public class ReflectTester { public Object copy(Object object) throws Exception{ //获得对象的类型 Class classType=object.getClass(); System.out.println("Class:"+classType.getName()); //通过默认构造方法创建一个新的对象 Object objectCopy=classType.getConstructor(new Class[]{}).newInstance(new Object[]{}); //获得对象的所有属性 Field fields[]=classType.getDeclaredFields(); for(int i=0; i Field field=fields[i]; String fieldName=field.getName(); String firstLetter=fieldName.substring(0,1).toUpperCase(); //获得和属性对应的getXXX()方法的名字 String getMethodName="get"+firstLetter+fieldName.substring(1); //获得和属性对应的setXXX()方法的名字 String setMethodName="set"+firstLetter+fieldName.substring(1); //获得和属性对应的getXXX()方法 Method getMethod=classType.getMethod(getMethodName,new Class[]{}); //获得和属性对应的setXXX()方法 Method setMethod=classType.getMethod(setMethodName,new Class[]{field.getType()}); //调用原对象的getXXX()方法 Object value=getMethod.invoke(object,new Object[]{}); System.out.println(fieldName+":"+value); //调用复制对象的setXXX()方法 etMethod.invoke(objectCopy,new Object[]{value}); } return objectCopy; } public static void main(String[] args) throws Exception{ Customer customer=new Customer("Tom",21); customer.setId(new Long(1)); Customer customerCopy=(Customer)new ReflectTester().copy(customer); System.out.println("Copy information:"+customerCopy.getName()+""+customerCopy.getAge()); }}class Customer{ //Customer类是一个JavaBean private Long id; private String name; private int age; public Customer(){} public Customer(String name,int age){ this.name=name; this.age=age; } public Long getId(){return id;} public void setId(Long id){this.id=id;} public String getName(){return name;} public void setName(String name){this.name=name;} public int getAge(){return age;} public void setAge(int age){this.age=age;}}
#p#
ReflectTester类的copy(Object object)方法依次执行以下步骤。
(1)获得对象的类型:
Class classType=object.getClass();System.out.println("Class:"+classType.getName());
在java.lang.Object类中定义了getClass()方法,因此对于任意一个Java对象,都可以通过此方法获得对象的类型。Class类是Reflection API中的核心类,它有以下方法。
◆getName():获得类的完整名字。
◆getFields():获得类的public类型的属性。
◆getDeclaredFields():获得类的所有属性。
◆getMethods():获得类的public类型的方法。
◆getDeclaredMethods():获得类的所有方法。
◆getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes参数指定方法的参数类型。
◆getConstrutors():获得类的public类型的构造方法。
◆getConstrutor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes参数指定构造方法的参数类型。
◆newInstance():通过类的不带参数的构造方法创建这个类的一个对象。
(2)通过默认构造方法创建一个新的对象:
Object objectCopy=classType.getConstructor(new Class[]{}).newInstance(new Object[]{});
以上代码先调用Class类的getConstructor()方法获得一个Constructor对象,它代表默认的构造方法,然后调用Constructor对象的newInstance()方法构造一个实例。
(3)获得对象的所有属性:
Field fields[]=classType.getDeclaredFields();
Class类的getDeclaredFields()方法返回类的所有属性,包括public、protected、默认和private访问级别的属性。
(4)获得每个属性相应的getXXX()和setXXX()方法,然后执行这些方法,把原来对象的属性复制到新的对象中:
for(int i=0; i Field field=fields[i]; String fieldName=field.getName(); String firstLetter=fieldName.substring(0,1).toUpperCase(); //获得和属性对应的getXXX()方法的名字 String getMethodName="get"+firstLetter+fieldName.substring(1); //获得和属性对应的setXXX()方法的名字 String setMethodName="set"+firstLetter+fieldName.substring(1); //获得和属性对应的getXXX()方法 Method getMethod=classType.getMethod(getMethodName,new Class[]{}); //获得和属性对应的setXXX()方法 Method setMethod=classType.getMethod(setMethodName,new Class[]{field.getType()}); //调用原对象的getXXX()方法 Object value=getMethod.invoke(object,new Object[]{}); System.out.println(fieldName+":"+value); //调用复制对象的setXXX()方法 setMethod.invoke(objectCopy,new Object[]{value});}
以上代码假定每个属性都有相应的getXXX()和setXXX()方法,并且在方法名中,“get”和“set”的后面一个字母为大写。例如,Customer类的name属性对应getName()和setName()方法。Method类的invoke(Object obj,Object args[])方法用于动态执行一个对象的特定方法,它的第一个obj参数指定具有该方法的对象,第二个args参数指定向该方法传递的参数。
如例程10-3所示的InvokeTester类的main()方法中,运用反射机制调用一个InvokeTester对象的add()和echo()方法。
例程10-3 InvokeTester.java
import java.lang.reflect.*;public class InvokeTester { public int add(int param1,int param2){ return param1+param2; } public String echo(String msg){ return "echo:"+msg; } public static void main(String[] args) throws Exception{ Class classType=InvokeTester.class; Object invokeTester=classType.newInstance(); //调用InvokeTester对象的add()方法 Method addMethod=classType.getMethod("add",new Class[]{int.class,int.class}); Object result=addMethod.invoke(invokeTester, new Object[]{new Integer(100),new Integer(200)}); System.out.println((Integer)result); //调用InvokeTester对象的echo()方法 Method echoMethod=classType.getMethod("echo",new Class[]{String.class}); result=echoMethod.invoke(invokeTester,new Object[]{"Hello"}); System.out.println((String)result); }}
add()方法的两个参数为int类型,获得表示add()方法的Method对象的代码如下:
Method addMethod=classType.getMethod("add",new Class[]{int.class,int.class});
Method类的invoke(Object obj,Object args[])方法接收的参数必须为对象,如果参数为基本类型数据,必须转换为相应的包装类型的对象。invoke()方法的返回值总是对象,如果实际被调用的方法的返回类型是基本类型数据,那么invoke()方法会把它转换为相应的包装类型的对象,再将其返回。
在本例中,尽管InvokeTester类的add()方法的两个参数及返回值都是int类型,调用addMethod对象的invoke()方法时,只能传递Integer类型的参数,并且invoke()方法的返回类型也是Integer类型,Integer类是int基本类型的包装类:
Object result=addMethod.invoke(invokeTester,new Object[]{new Integer(100),new Integer(200)});System.out.println((Integer)result); //result为Integer类型
java.lang.Array类提供了动态创建和访问数组元素的各种静态方法。如例程10-4所示的ArrayTester1类的main()方法创建了一个长度为10的字符串数组,接着把索引位置为5的元素设为“hello”,然后再读取索引位置为5的元素的值。
#p#
例程10-4 ArrayTester1.java
import java.lang.reflect.*;public class ArrayTester1 { public static void main(String args[])throws Exception { Class classType = Class.forName("java.lang.String"); //创建一个长度为10的字符串数组 Object array = Array.newInstance(classType, 10); //把索引位置为5的元素设为"hello" Array.set(array, 5, "hello"); //读取索引位置为5的元素的值 String s = (String) Array.get(array, 5); System.out.println(s); }}
如例程10-5所示的ArrayTester2类的main()方法创建了一个5×10×15的整型数组,并把索引位置为[3][5][10]的元素的值为设37。
例程10-5 ArrayTester2.java
import java.lang.reflect.*;public class ArrayTester2{ public static void main(String args[]) { int dims[] = new int[]{5, 10, 15}; Object array = Array.newInstance(Integer.TYPE, dims); //使arrayObj引用array[3] Object arrayObj = Array.get(array, 3); Class cls = arrayObj.getClass().getComponentType(); System.out.println(cls); //使arrayObj引用array[3][5] arrayObj = Array.get(arrayObj, 5); //把元素array[3][5][10]设为37 Array.setInt(arrayObj, 10, 37); int arrayCast[][][] = (int[][][]) array; System.out.println(arrayCast[3][5][10]); }}
10.2 在远程方法调用中运用反射机制
假定在SimpleServer服务器端创建了一个HelloServiceImpl对象,它具有getTime()和echo()方法。HelloServiceImpl类实现了HelloService接口。如例程10-6和例程10-7所示分别是HelloService接口和HelloServiceImpl类的源程序。
例程10-6 HelloService.java
package remotecall;import java.util.Date;public interface HelloService{ public String echo(String msg); public Date getTime();}
例程10-7 HelloServiceImpl.java
package remotecall;import java.util.Date;public class HelloServiceImpl implements HelloService{ public String echo(String msg){ return "echo:"+msg; } public Date getTime(){ return new Date(); }}
SimpleClient客户端如何调用服务器端的HelloServiceImpl对象的getTime()和echo()方法呢?显然,SimpleClient客户端需要把调用的方法名、方法参数类型、方法参数值,以及方法所属的类名或接口名发送给SimpleServer,SimpleServer再调用相关对象的方法,然后把方法的返回值发送给SimpleClient。
为了便于按照面向对象的方式来处理客户端与服务器端的通信,可以把它们发送的信息用Call类(如例程10-8所示)来表示。一个Call对象表示客户端发起的一个远程调用,它包括调用的类名或接口名、方法名、方法参数类型、方法参数值和方法执行结果。
例程10-8 Call.java
package remotecall;import java.io.*;public class Call implements Serializable{ private String className; //表示类名或接口名 private String methodName; //表示方法名 private Class[] paramTypes; //表示方法参数类型private Object[] params; //表示方法参数值//表示方法的执行结果//如果方法正常执行,则result为方法返回值,如果方法抛出异常,那么result为该异常。 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 void setClassName(String className){this.className=className;} public String getMethodName(){return methodName;} public void setMethodName(String methodName){this.methodName=methodName;} public Class[] getParamTypes(){return paramTypes;} public void setParamTypes(Class[] paramTypes){this.paramTypes=paramTypes;} public Object[] getParams(){return params;} public void setParams(Object[] params){this.params=params;} public Object getResult(){return result;} public void setResult(Object result){this.result=result;} public String toString(){ return "className="+className+" methodName="+methodName; }}
SimpleClient调用SimpleServer端的HelloServiceImpl对象的echo()方法的流程如下。
(1)SimpleClient创建一个Call对象,它包含了调用HelloService接口的echo()方法的信息。
(2)SimpleClient通过对象输出流把Call对象发送给SimpleServer。
(3)SimpleServer通过对象输入流读取Call对象,运用反射机制调用HelloServiceImpl对象的echo()方法,把echo()方法的执行结果保存到Call对象中。
(4)SimpleServer通过对象输出流把包含了方法执行结果的Call对象发送给SimpleClient。
(5)SimpleClient通过对象输入流读取Call对象,从中获得方法执行结果。
#p#
如例程10-9和例程10-10所示分别是SimpleServer和SimpleClient的源程序。
例程10-9 SimpleServer.java
package remotecall;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("remotecall.HelloService",new HelloServiceImpl()); server.service(); }}
例程10-10 SimpleClient.java
package remotecall;import java.io.*;import java.net.*;import java.util.*;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("remotecall.HelloService","getTime",new Class[]{},new Object[]{}); Call call=new Call("remotecall.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(); }}
先运行命令“java remotecall.SimpleServer”,再运行命令“java remotecall. SimpleClient”,SimpleClient端将打印“echo:Hello”。该打印结果是服务器端执行HelloServiceImpl对象的echo()方法的返回值。如图10-1所示显示了SimpleClient与SimpleServer的通信过程。
发表评论
-
Spring Gateway 接口返回值脱敏
2023-10-20 09:55 2018package com.huatech.gateway.f ... -
logback 常用配置及说明
2020-05-28 15:41 730<?xml version="1.0& ... -
springboot中增强druid实现数据库账号密码加解密
2020-03-11 13:31 1582针对目前越来越严的安全等级要求,我们在做产品 ... -
java常用命令
2020-01-14 13:25 1114# 1、查询java进程id jps -v ... -
poi excel导入工具类
2019-11-20 14:00 737poi excel导入工具类ImportUtil i ... -
通过spring-context创建可执行jar
2019-04-23 13:52 11211、新建一个maven工程; 2、pom.xml中 ... -
什么情况下Java程序会产生死锁?如何定位和修复死锁
2019-04-18 20:38 1455死锁是一种特定的程序状态,在实体之间,由于循环依赖导致彼此 ... -
反射机制和动态代理的原理
2019-04-13 14:02 2003反射机制是Java语言提供的一种基础功能,赋予程序在运行时 ... -
String、StringBuffer、StringBuilder的区别?
2019-04-13 10:00 762Java的基本类型有八种 ... -
强引用、软引用、弱引用、幻象引用有什么区别?具体使用场景是什么?
2019-04-12 15:10 762在 Java 语言中,除了原始数据类型的变量,其他 ... -
Exception与Error的区别?
2019-04-11 09:25 574Java语言在设计之初就 ... -
应用国际化(3)
2018-12-27 21:13 840前两篇介绍了应用国际化的注意事项和提示语国际化的简单实现。后 ... -
应用国际化(2)
2018-12-26 20:39 819上一篇介绍了应用国际化需要考虑的问题,本篇介绍后端如何实现 ... -
应用国际化(1)
2018-12-26 20:08 839最近在做数字资产交 ... -
性能优化实战-2
2018-09-28 10:15 1185我们在做架构设计的时候,会提到几个关键词:高性能、高 ... -
性能优化实战-1
2018-09-27 20:04 1128系统优化大致可以分 ... -
rabbitmq批量处理
2018-04-08 17:35 9454我们通过spring-amqp操作rabbitmq是极其简 ... -
java进程CPU过高问题定位
2018-03-14 09:06 23091、top命令查看过高CPU的pid,命令:top ... -
spring-boot集成RabbitMQ
2018-01-16 16:38 1320RabbitMQ的安装不在此赘述,想了解的可以参考: ... -
重写DispatcherServlet获取springmvc 所有RequestMapping的url
2018-01-09 10:41 30781、重写DispatcherServlet i ...
相关推荐
java反射机制java反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制...
JAVA反射机制应用 JAVA反射机制是JAVA语言中的一种动态机制,它能够在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法。这种动态获取的信息以及动态...
Java反射机制是Java编程语言中的一个强大特性,它允许程序在运行时检查和操作类、接口、对象等的内部信息。通过Java反射机制,开发者可以在不知道具体类名的情况下创建对象,调用方法,访问和修改私有成员变量,以及...
Java反射机制是Java编程语言中的一个重要特性,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。在Java中,反射机制的核心类集中在java.lang.reflect包下,包括Class、Constructor、Method和...
### Java反射机制深入理解 #### 一、反射机制概述 Java反射机制是一种强大的工具,它允许程序在运行时检查和操作任何类、方法、构造函数和字段等元素。这种能力对于构建灵活的应用程序和框架非常有用,特别是那些...
Java反射机制是Java语言提供的一种强大工具,它允许在程序运行时动态地获取类的信息以及对类的对象进行操作。在Java中,静态编译时类型检查确保了代码的稳定性,但有时我们需要在运行时根据需求动态地创建对象、调用...
Java反射机制是Java编程语言中的一个强大特性,它允许程序在运行时检查和操作类、接口、对象等的内部结构。通过反射,开发者可以动态地获取类的信息并调用其方法,创建对象,访问私有成员,甚至改变类的行为。在深入...
Java反射机制是Java编程语言中的一个重要特性,它允许程序在运行时获取和操作任何已知名称的类的内部信息。这一机制使得Java具备了一定的动态性,虽然在传统的分类中Java被视为静态类型语言。通过反射,开发者可以在...
Java 反射机制是 Java 语言中的一个重要特性,它允许程序在运行时动态地获取类的信息(如类名、属性、方法等)并调用对象的方法,甚至修改对象的状态。这一机制极大地增强了 Java 程序的灵活性和可扩展性,尤其是在...
这篇博文"Java反射机制学习(二)"可能深入探讨了如何利用反射进行动态类型处理、访问私有成员以及创建对象等核心概念。在这里,我们将详细讨论Java反射的基本用法及其在实际开发中的应用。 1. **什么是反射**: ...
java反射机制和动态代理的原理,熟悉反射机制和动态代理
### Java反射机制详解 #### 一、Java反射机制概述 Java反射机制是Java语言的一个重要特性,它允许程序在运行时获取类的信息并操作对象。Java反射机制的主要作用包括:获取类的所有属性和方法、构造动态实例、调用...
Java反射机制是Java编程语言中的一个重要特性,它允许程序在运行时动态地获取类的信息并操作类的对象。这种机制使得Java具有高度的灵活性和动态性,可以在编译时未知类的情况下进行类的加载、实例化、方法调用等操作...
Java反射机制是Java编程语言中的一个强大特性,它允许程序在运行时检查和操作类、接口、字段和方法的信息。这个特性使得Java具备了高度的灵活性,能够在运行时动态地发现和使用类的属性和方法,即使这些信息在编译时...
Java反射机制是Java编程语言中的一个强大特性,它允许程序在运行时检查并操作类、接口、字段和方法的信息,打破了通常编译时静态绑定的限制。通过反射,我们可以动态地创建对象,调用方法,访问和修改字段值,甚至...
### Java反射机制详解 #### 一、引言 在Java面试中,经常会出现与反射机制相关的题目。这是因为Java反射机制不仅是Java语言的一项重要特性,也是理解Java动态特性的关键所在。通过本文,我们将深入探讨Java反射...
java反射机制核心代码,小弟一直弄不明白,怎么通过反射来调用私有成员方法,看了这个后,你可以随心调用private方法,和属性,记得添加setAccessable(true),哦,要不还是不行,如:method.setAccessable(true);
Java反射机制是Java编程语言中的一个重要特性,它允许程序在运行时动态地获取类的信息并进行操作。通过反射,开发者可以在程序执行时发现并访问类的字段(fields)、方法(methods)以及构造器(constructors),...