《Java网络编程精解讲义10.ppt》由会员分享,可在线阅读,更多相关《Java网络编程精解讲义10.ppt(43页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、Java网络编程精解作者:孙卫琴作者:孙卫琴作者:孙卫琴作者:孙卫琴参考书籍:参考书籍:参考书籍:参考书籍:技术支持网址:技术支持网址:技术支持网址:技术支持网址:www.javathinker.orgwww.javathinker.org第10章 Java反射机制参考Java网络编程精解的第10章n10.1 Java Reflection API简介n10.2 在远程方法调用中运用反射机制n10.3 代理模式n10.3.1 静态代理类n10.3.2 动态代理类n10.3.3 在远程方法调用中运用代理类第10章 Java反射机制nJava反射机制主要提供了以下功能:n在运行时判断任意一个对象所
2、属的类。n在运行时构造任意一个类的对象。n在运行时判断任意一个类所具有的成员变量和方法。n在运行时调用任意一个对象的方法。n生成动态代理。10.1 Java Reflection API简介n在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中:nClass类:代表一个类。nField类:代表类的成员变量(成员变量也称为类的属性)。nMethod类:代表类的方法。nConstructor类:代表类的构造方法。nArray类:提供了动态创建数组,以及访问数组的元素的静态方法。10.1 Java Reflection API简介n例程10-2的Refl
3、ectTester类演示了Reflection API的基本使用方法。nReflectTester类有一个copy(Object object)方法,这个方法能够创建一个和参数object同样类型的对象,然后把object对象中的所有属性拷贝到新建的对象中,并将它返回。10.1 Java Reflection API简介ReflectTester类的copy(Object object)方法依次执行以下步骤。n步骤1:获得对象的类型:Class classType=object.getClass();System.out.println(Class:+classType.getName();n
4、在java.lang.Object类中定义了getClass()方法,因此对于任意一个Java对象,都可以通过此方法获得对象的类型。10.1 Java Reflection API简介nClass类是Reflection API中的核心类,它有以下方法:ngetName():获得类的完整名字。ngetFields():获得类的public类型的属性。ngetDeclaredFields():获得类的所有属性。ngetMethods():获得类的public类型的方法。ngetDeclaredMethods():获得类的所有方法。ngetMethod(String name,Class para
5、meterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes参数指定方法的参数类型。ngetConstrutors():获得类的public类型的构造方法。ngetConstrutor(Class parameterTypes):获得类的特定构造方法,parameterTypes参数指定构造方法的参数类型。nnewInstance():通过类的不带参数的构造方法创建这个类的一个对象。10.1 Java Reflection API简介nReflectTester类的copy(Object object)方法执行的步骤2:通过默认构造方法创建一个新的对象。O
6、bject objectCopy=classType.getConstructor(new Class).newInstance(new Object);n以上代码先调用Class类的getConstructor()方法获得一个Constructor对象,它代表默认的构造方法,然后调用Constructor对象的newInstance()方法构造一个实例。10.1 Java Reflection API简介nReflectTester类的copy(Object object)方法执行的步骤3:获得对象的所有属性。Field fields=classType.getDeclaredFields(
7、);nClass类的getDeclaredFields()方法返回类的所有属性,包括public、protected、默认和private访问级别的属性。10.1 Java Reflection API简介nReflectTester类的copy(Object object)方法执行的步骤4:获得每个属性相应的getXXX()和setXXX()方法,然后执行这些方法,把原来对象的属性拷贝到新的对象中。1.for(int i=0;ifields.length;i+)2.Field field=fieldsi;3.String fieldName=field.getName();4.String
8、firstLetter=fieldName.substring(0,1).toUpperCase();5./获得和属性对应的getXXX()方法的名字6.String getMethodName=get+firstLetter+fieldName.substring(1);7./获得和属性对应的setXXX()方法的名字8.String setMethodName=set+firstLetter+fieldName.substring(1);10.1 Java Reflection API简介9./获得和属性对应的getXXX()方法10.Method getMethod=classType.
9、getMethod(getMethodName,new Class);11./获得和属性对应的setXXX()方法12.Method setMethod=classType.getMethod(setMethodName,new Classfield.getType();13./调用原对象的getXXX()方法14.Object value=getMethod.invoke(object,new Object);15.System.out.println(fieldName+:+value);16./调用拷贝对象的setXXX()方法17.setMethod.invoke(objectCopy
10、,new Objectvalue);18.10.1 Java Reflection API简介n例程10-3的InvokeTester类的main()方法中,运用反射机制调用一个InvokeTester对象的add()和echo()方法。nadd()方法的两个参数为int类型,获得表示add()方法的Method对象的代码如下:Method addMethod=classType.getMethod(add,new Classint.class,int.class);nMethod类的invoke(Object obj,Object args)方法接收的参数必须为对象,如果参数为基本类型数据,
11、必须转换为相应的包装类型的对象。invoke()方法的返回值总是对象,如果实际被调用的方法的返回类型是基本类型数据,那么invoke()方法会把它转换为相应的包装类型的对象,再将其返回。10.2 在远程方法调用中运用反射机制n假定在SimpleServer服务器端创建了一个HelloServiceImpl对象,它具有getTime()和echo()方法。HelloServiceImpl类实现了HelloService接口。例程10-6 HelloService.javapackage remotecall;import java.util.Date;public interface Hello
12、Service public String echo(String msg);public Date getTime();10.2 在远程方法调用中运用反射机制nSimpleClient客户端如何调用服务器端的HelloServiceImpl对象的getTime()和echo()方法呢?n显然,SimpleClient客户端需要把调用的方法名、方法参数类型、方法参数值,以及方法所属的类名或接口名发送给SimpleServer,SimpleServer再调用相关对象的方法,然后把方法的返回值发送给SimpleClient。10.2 在远程方法调用中运用反射机制n为了便于按照面向对象的方式来处理客
13、户端与服务器端的通信,可以把它们发送的信息用Call类(参见例程10-8)来表示。一个Call对象表示客户端发起的一个远程调用,它包括调用的类名或接口名、方法名、方法参数类型、方法参数值和方法执行结果。例程10-8 Call.java1.package remotecall;2.import java.io.*;3.public class Call implements Serializable4.private String className;/表示类名或接口名5.private String methodName;/表示方法名6.private Class paramTypes;/表示
14、方法参数类型7.private Object params;/表示方法参数值10.2 在远程方法调用中运用反射机制8./表示方法的执行结果9./如果方法正常执行,则result为方法返回值,如果方法抛出异常,那么result为该异常。10.private Object result;11.12.public Call()13.public Call(String className,String methodName,Class paramTypes,14.Object params)15.this.className=className;16.this.methodName=methodNa
15、me;17.this.paramTypes=paramTypes;18.this.params=params;19.20.21.public String getClassName()return className;22.public void setClassName(String className)this.className=className;10.2 在远程方法调用中运用反射机制23.public String getMethodName()return methodName;24.public void setMethodName(String methodName)this.
16、methodName=methodName;25.public Class getParamTypes()return paramTypes;26.public void setParamTypes(Class paramTypes)this.paramTypes=paramTypes;27.public Object getParams()return params;28.public void setParams(Object params)this.params=params;29.public Object getResult()return result;30.public void
17、 setResult(Object result)this.result=result;31.public String toString()32.return className=+className+methodName=+methodName;33.34.10.2 在远程方法调用中运用反射机制nSimpleClient调用SimpleServer端的HelloServiceImpl对象的echo()方法的流程如下。n(1)SimpleClient创建一个Call对象,它包含了调用HelloService接口的echo()方法的信息。n(2)SimpleClient通过对象输出流把Call
18、对象发送给SimpleServer。n(3)SimpleServer通过对象输入流读取Call对象,运用反射机制调用HelloServiceImpl对象的echo()方法,把echo()方法的执行结果保存到Call对象中。n(4)SimpleServer通过对象输出流把包含了方法执行结果的Call对象发送给SimpleClient。n(5)SimpleClient通过对象输入流读取Call对象,从中获得方法执行结果。10.2 在远程方法调用中运用反射机制n图10-1显示了SimpleClient与SimpleServer的通信过程。10.3 代理模式n代理模式是常用的Java设计模式,它的特征
19、是:代理类与委托类有同样的接口,参见图10-2。10.3 代理模式n按照代理类的创建时期,代理类可分为两种:n静态代理类:由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。n动态代理类:在程序运行时,运用反射机制动态创建而成。10.3.1 静态代理类n如图10-3所示,HelloServiceProxy类是代理类,HelloServiceImpl类是委托类,这两个类都实现了HelloService接口。n其中HelloServiceImpl类是HelloService接口的真正实现者,而HelloServiceProxy类是通过调用Hell
20、oServiceImpl类的相关方法来提供特定服务的。10.3.1 静态代理类例程10-11 HelloService.javapackage proxy;import java.util.Date;public interface HelloService public String echo(String msg);public Date getTime();10.3.1 静态代理类n在Client1类(参见例程10-14)的main()方法中,先创建了一个HelloServiceImpl对象,再创建了一个HelloServiceProxy对象,最后调用HelloServiceProxy对
21、象的echo()方法。例程10-14 Client1.javapackage proxy;public class Client1 public static void main(String args)HelloService helloService=new HelloServiceImpl();HelloService helloServiceProxy=new HelloServiceProxy(helloService);System.out.println(helloServiceProxy.echo(hello);10.3.1 静态代理类n图10-4显示了Client1调用Hel
22、loServiceProxy类的echo()方法的时序图。10.3.2 动态代理类n与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。n动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java反射机制可以生成任意类型的动态代理类。njava.lang.reflect包中的Proxy类和InvocationHandler接口提供了生成动态代理类的能力。10.3.2 动态代理类nProxy类提供了创建动态代理类及其的实例的静态方法:n(1)getProxyClass()静态方法负责创建动态代理类,它的完整定义如下
23、:public static Class getProxyClass(ClassLoader loader,Class interfaces)throws IllegalArgumentException参数loader指定动态代理类的类加载器,参数interfaces指定动态代理类需要实现的所有接口。n(2)newProxyInstance()静态方法负责创建动态代理类的实例,它的完整定义如下:public static Object newProxyInstance(ClassLoader loader,Class interfaces,InvocationHandler handler)
24、throws IllegalArgumentException参数loader指定动态代理类的类加载器,参数interfaces指定动态代理类需要实现的所有接口,参数handler指定与动态代理类关联的 InvocationHandler对象。10.3.2 动态代理类n以下两种方式都创建了实现Foo接口的动态代理类的实例:/*方式一 */创建InvocationHandler对象 InvocationHandler handler=new MyInvocationHandler(.);/创建动态代理类 Class proxyClass=Proxy.getProxyClass(Foo.class
25、.getClassLoader(),new Class Foo.class);/创建动态代理类的实例 Foo foo=(Foo)proxyClass.getConstructor(new Class InvocationHandler.class).newInstance(new Object handler);/*方式二 */创建InvocationHandler对象 InvocationHandler handler=new MyInvocationHandler(.);/直接创建动态代理类的实例 Foo foo=(Foo)Proxy.newProxyInstance(Foo.class.
26、getClassLoader(),new Class Foo.class,handler);10.3.2 动态代理类nInvocationHandler接口为方法调用接口,它声明了负责调用任意一个方法的invoke()方法:Object invoke(Object proxy,Method method,Object args)throws Throwablen参数proxy指定动态代理类实例,参数method指定被调用的方法,参数args指定向被调用方法传递的参数,invoke()方法的返回值表示被调用方法的返回值。10.3.2 动态代理类n如图10-5所示,HelloServiceProx
27、yFactory类的getHelloServiceProxy()静态方法负责创建实现了HelloService接口的动态代理类的实例。10.3.2 动态代理类n例程10-16的Client2类先创建了一个HelloServiceImpl实例,然后创建了一个动态代理类实例helloServiceProxy,最后调用动态代理类实例的echo()方法。例程10-16 Client2.javapackage proxy;public class Client2 public static void main(String args)HelloService helloService=new Hello
28、ServiceImpl();HelloService helloServiceProxy=HelloServiceProxyFactory.getHelloServiceProxy(helloService);System.out.println(动态代理类的名字为 +helloServiceProxy.getClass().getName();System.out.println(helloServiceProxy.echo(Hello);10.3.2 动态代理类n图10-6显示了Client2调用动态代理类$Proxy0的实例helloServiceProxy的echo()方法的时序图。1
29、0.3.3 在远程方法调用中运用代理类n如图10-7所示,SimpleClient客户端通过HelloService代理类来调用SimpleServer服务器端的HelloServiceImpl对象的方法。n客户端的HelloService代理类也实现了HelloService接口,这可以简化SimpleClient客户端的编程。n对于SimpleClient客户端而言,与远程服务器的通信的细节被封装到HelloService代理类中。10.3.3 在远程方法调用中运用代理类nSimpleClient客户端可以按照以下方式调用远程服务器上的HelloServiceImpl对象的方法:/创建He
30、lloService代理类的对象HelloService helloService1=new HelloServiceProxy(connector);/通过代理类调用远程服务器上的HelloServiceImpl对象的方法System.out.println(helloService1.echo(hello);10.3.3 在远程方法调用中运用代理类nConnector类负责建立与远程服务器的连接,以及接收和发送Socket对象,参见例程10-17。例程10-17 Connector.javapublic class Connector public Connector(String hos
31、t,int port)throws Exception.public void send(Object obj)throws Exception /发送对象 oos.writeObject(obj);public Object receive()throws Exception /接收对象 return ois.readObject();public void connect()throws Exception /建立与远程服务器的连接 connect(host,port);public void connect(String host,int port)throws Exception.10
32、.3.3 在远程方法调用中运用代理类nHelloService代理类有两种创建方式:n一种方式是创建一个HelloServiceProxy静态代理类,参见例程10-18;n还有一种方式是创建HelloService的动态代理类,例程10-19的ProxyFactory类的静态getProxy()方法就负责创建HelloService的动态代理类,并且返回它的一个实例。10.3.3 在远程方法调用中运用代理类n无论是HelloService的静态代理类还是动态代理类,都通过Connector类来发送和接收Call对象。nProxyFactory工厂类的getProxy()方法的第一个参数clas
33、sType指定代理类实现的接口的类型,如果参数classType的取值为HelloService.class,那么getProxy()方法就创建HelloService动态代理类的实例,如果参数classType的取值为Foo.class,那么getProxy()方法就创建Foo动态代理类的实例。n由此可见,getProxy()方法可以创建任意类型的动态代理类的实例,并且它们都具有调用被代理的远程对象的方法的能力。10.3.3 在远程方法调用中运用代理类n在例程10-20的SimpleClient类的main()方法中,分别通过静态代理类和动态代理类去访问SimpleServer服务器上的He
34、lloServiceImpl对象的各种方法。public static void main(String args)throws Exception /创建静态代理类实例 HelloService helloService1=new HelloServiceProxy(localhost,8000);System.out.println(helloService1.echo(hello);System.out.println(helloService1.getTime();/创建动态代理类实例 HelloService helloService2=(HelloService)ProxyFact
35、ory.getProxy(HelloService.class,localhost,8000);System.out.println(helloService2.echo(hello);System.out.println(helloService2.getTime();10.3.3 在远程方法调用中运用代理类n图10-8显示了SimpleClient通过HelloService静态代理类访问远程HelloServiceImpl对象的echo()方法的时序图。10.3.3 在远程方法调用中运用代理类n图10-9显示了SimpleClient通过HelloService动态代理类访问远程Hell
36、oServiceImpl对象的echo()方法的时序图。练习题1n问题:以下哪些方法在问题:以下哪些方法在Class类中定义?类中定义?n选项选项:na)getConstructors()nb)getPrivateMethods()nc)getDeclaredFields()nd)getImports()ne)setField()n答案答案:a,c练习题2n问题:以下哪些说法正确?问题:以下哪些说法正确?n选项选项:na)动态代理类与静态代码类一样,必须由开发人员先编写源代码,动态代理类与静态代码类一样,必须由开发人员先编写源代码,并编译成并编译成.class文件。文件。nb)代理类与被代理类
37、的具有同样的接口。代理类与被代理类的具有同样的接口。nc)java.lang.Exception类实现了类实现了java.io.Serializable接口,因此接口,因此Exception对象可以在网络上传输。对象可以在网络上传输。nd)java.lang.reflect包中的包中的Proxy类提供了创建动态代理类的方法。类提供了创建动态代理类的方法。n答案答案:b,c,d练习题3n问题:问题:以下哪些属于动态代理类的特点?以下哪些属于动态代理类的特点?n选项选项:na)动态代理类是动态代理类是public、final和非抽象类型的。和非抽象类型的。nb)动态代理类继承了动态代理类继承了java.lang.reflect.Proxy类。类。nc)动态代理类实现动态代理类实现getProxyClass()和和newProxyInstance()方法中参数方法中参数interfaces指定的所有接口。指定的所有接口。nd)动态代理类可以继承用户自定义的任意类。动态代理类可以继承用户自定义的任意类。ne)动态代理类都具有一个动态代理类都具有一个public类型的构造方法,该构造方类型的构造方法,该构造方法有一个法有一个InvocationHandler类型的参数。类型的参数。n答案答案:a,b,c,e
限制150内