第十五章Java反射机制与正则表达式.docx
- 文档编号:2920991
- 上传时间:2023-05-05
- 格式:DOCX
- 页数:37
- 大小:134.52KB
第十五章Java反射机制与正则表达式.docx
《第十五章Java反射机制与正则表达式.docx》由会员分享,可在线阅读,更多相关《第十五章Java反射机制与正则表达式.docx(37页珍藏版)》请在冰点文库上搜索。
第十五章Java反射机制与正则表达式
第十五章Java反射机制与正则表达式
学习目标
Ø理解Java反射机制的概念。
Ø能够上机对Java反射机制类和方法进行操作。
Ø掌握Java反射机制在远程调用中的控制。
课前准备
Ø掌握Java关于类与方法的概念与应用。
Ø了解代理模式。
15.1本章简介
反射的概念主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。
通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examination),并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
允许运行中的Java程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性。
这种动态获取类的信息,以及动态调用对象的方法的功能来自于Java语言的反射(Reflection)机制。
Java反射机制主要提供了以下功能:
●在运行时判断任意一个对象所属的类;
●在运行时构造任意一个类的对象;
●在运行时判断任意一个类所具有的成员变量和方法;
●在运行时调用任意一个对象的方法;
●生成动态代理。
本章首先介绍了JavaReflectionAPI的用法,然后介绍了一个远程方法调用的例子,在这个例子中客户端能够远程调用服务器端的一个对象的方法。
服务器端采用了反射机制提供的动态调用方法的功能,而客户端则采用了反射机制提供的动态代理功能。
15.2JavaReflectionAPI简介
在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中。
●Class类:
代表一个类。
●Field类:
代表类的成员变量(成员变量也称为类的属性)。
●Method类:
代表类的方法。
●Constructor类:
代表类的构造方法。
●Array类:
提供了动态创建数组,以及访问数组元素的静态方法。
如代码15-1所示DumpMethods类演示了ReflectionAPI的基本作用,它读取命令行参数指定的类名,然后打印这个类所具有的方法信息:
代码15-1DumpMethods.java
importjava.lang.reflect.*;
publicclassDumpMethods{
publicstaticvoidmain(Stringargs[])throwsException{
//加载并初始化命令行参数指定的类
ClassclassType=Class.forName(args[0]);
//获得类的所有方法
Methodmethods[]=classType.getDeclaredMethods();
for(inti=0;i System.out.println(methods[i].toString()); } } 运行命令"javaDumpMethodsjava.util.Stack",就会显示java.util.Stack类所具有的方法,程序的打印结果如下: publicsynchronizedjava.lang.Objectjava.util.Stack.pop() publicjava.lang.Objectjava.util.Stack.push(java.lang.Object) publicbooleanjava.util.Stack.empty() publicsynchronizedjava.lang.Objectjava.util.Stack.peek() publicsynchronizedintjava.util.Stack.search(java.lang.Object) 如代码15-2所示ReflectTester类进一步演示了ReflectionAPI的基本使用方法。 ReflectTester类有一个copy(Objectobject)方法,这个方法能够创建一个和参数object同样类型的对象,然后把object对象中的所有属性复制到新建的对象中,并将它返回。 这个例子只能复制简单的JavaBean,假定JavaBean的每个属性都有public类型的getXXX()和setXXX()方法。 代码15-2ReflectTester.java importjava.lang.reflect.*; publicclassReflectTester{ publicObjectcopy(Objectobject)throwsException{ //获得对象的类型 ClassclassType=object.getClass(); System.out.println("Class: "+classType.getName()); //通过默认构造方法创建一个新的对象 ObjectobjectCopy=classType.getConstructor(newClass[]{}).newInstance(newObject[]{}); //获得对象的所有属性 Fieldfields[]=classType.getDeclaredFields(); for(inti=0;i Fieldfield=fields[i]; StringfieldName=field.getName(); StringfirstLetter=fieldName.substring(0,1).toUpperCase(); //获得和属性对应的getXXX()方法的名字 StringgetMethodName="get"+firstLetter+fieldName.substring (1); //获得和属性对应的setXXX()方法的名字 StringsetMethodName="set"+firstLetter+fieldName.substring (1); //获得和属性对应的getXXX()方法 MethodgetMethod=classType.getMethod(getMethodName,newClass[]{}); //获得和属性对应的setXXX()方法 MethodsetMethod=classType.getMethod(setMethodName,newClass[]{field.getType()}); //调用原对象的getXXX()方法 Objectvalue=getMethod.invoke(object,newObject[]{}); System.out.println(fieldName+": "+value); //调用复制对象的setXXX()方法 setMethod.invoke(objectCopy,newObject[]{value}); } returnobjectCopy; } publicstaticvoidmain(String[]args)throwsException{ Customercustomer=newCustomer("Tom",21); customer.setId(newLong (1)); CustomercustomerCopy=(Customer)new ReflectTester().copy(customer); System.out.println("Copyinformation: "+customerCopy.getName()+"+"+ customerCopy.getAge()); } } classCustomer{//Customer类是一个JavaBean privateLongid; privateStringname; privateintage; publicCustomer(){} publicCustomer(Stringname,intage){ this.name=name; this.age=age; } publicLonggetId(){returnid;} publicvoidsetId(Longid){this.id=id;} publicStringgetName(){returnname;} publicvoidsetName(Stringname){this.name=name;} publicintgetAge(){returnage;} publicvoidsetAge(intage){this.age=age;} } ReflectTester类的copy(Objectobject)方法依次执行以下步骤。 (1)获得对象的类型: ClassclassType=object.getClass(); System.out.println("Class: "+classType.getName()); 在java.lang.Object类中定义了getClass()方法,因此对于任意一个Java对象,都可以通过此方法获得对象的类型。 Class类是ReflectionAPI中的核心类,它有以下方法。 ●getName(): 获得类的完整名字。 ●getFields(): 获得类的public类型的属性。 ●getDeclaredFields(): 获得类的所有属性。 ●getMethods(): 获得类的public类型的方法。 ●getDeclaredMethods(): 获得类的所有方法。 ●getMethod(Stringname,Class[]parameterTypes): 获得类的特定方法,name参数指定方法的名字,parameterTypes参数指定方法的参数类型。 ●getConstrutors(): 获得类的public类型的构造方法。 ●getConstrutor(Class[]parameterTypes): 获得类的特定构造方法,parameterTypes参数指定构造方法的参数类型。 ●newInstance(): 通过类的不带参数的构造方法创建这个类的一个对象。 (2)通过默认构造方法创建一个新的对象: ObjectobjectCopy=classType.getConstructor(newClass[]{}).newInstance(newObject[]{}); 以上代码先调用Class类的getConstructor()方法获得一个Constructor对象,它代表默认的构造方法,然后调用Constructor对象的newInstance()方法构造一个实例。 (3)获得对象的所有属性: Fieldfields[]=classType.getDeclaredFields(); Class类的getDeclaredFields()方法返回类的所有属性,包括public、protected、默认和private访问级别的属性。 (4)获得每个属性相应的getXXX()和setXXX()方法,然后执行这些方法,把原来对象的属性复制到新的对象中: for(inti=0;i Fieldfield=fields[i]; StringfieldName=field.getName(); StringfirstLetter=fieldName.substring(0,1).toUpperCase(); //获得和属性对应的getXXX()方法的名字 StringgetMethodName="get"+firstLetter+fieldName.substring (1); //获得和属性对应的setXXX()方法的名字 StringsetMethodName="set"+firstLetter+fieldName.substring (1); //获得和属性对应的getXXX()方法 MethodgetMethod=classType.getMethod(getMethodName,newClass[]{}); //获得和属性对应的setXXX()方法 MethodsetMethod=classType.getMethod(setMethodName,newClass[]{field.getType()} //调用原对象的getXXX()方法 Objectvalue=getMethod.invoke(object,newObject[]{}); System.out.println(fieldName+": "+value); //调用复制对象的setXXX()方法 setMethod.invoke(objectCopy,newObject[]{value}); } Method类的invoke(Objectobj,Objectargs[])方法用于动态执行一个对象的特定方法,它的第一个obj参数指定具有该方法的对象,第二个args参数指定向该方法传递的参数。 如代码15-3所示的InvokeTester类的main()方法中,运用反射机制调用一个InvokeTester对象的add()和echo()方法。 代码15-3InvokeTester.java importjava.lang.reflect.*; publicclassInvokeTester{ publicintadd(intparam1,intparam2){ returnparam1+param2; } publicStringecho(Stringmsg){ return"echo: "+msg; } publicstaticvoidmain(String[]args)throwsException{ ClassclassType=InvokeTester.class; ObjectinvokeTester=classType.newInstance(); //调用InvokeTester对象的add()方法 MethodaddMethod=classType.getMethod ("add",newClass[]{int.class,int.class}); Objectresult=addMethod.invoke(invokeTester, newObject[]{newInteger(100),newInteger(200)}); System.out.println((Integer)result); //调用InvokeTester对象的echo()方法 MethodechoMethod=classType.getMethod ("echo",newClass[]{String.class}); result=echoMethod.invoke(invokeTester,newObject[]{"Hello"}); System.out.println((String)result); } } add()方法的两个参数为int类型,获得表示add()方法的Method对象的代码如下: MethodaddMethod=classType.getMethod("add",newClass[]{int.class,int.class}); Method类的invoke(Objectobj,Objectargs[])方法接收的参数必须为对象,如果参数为基本类型数据,必须转换为相应的包装类型的对象。 invoke()方法的返回值总是对象,如果实际被调用的方法的返回类型是基本类型数据,那么invoke()方法会把它转换为相应的包装类型的对象,再将其返回。 在本例中,尽管InvokeTester类的add()方法的两个参数及返回值都是int类型,调用addMethod对象的invoke()方法时,只能传递Integer类型的参数,并且invoke()方法的返回类型也是Integer类型,Integer类是int基本类型的包装类: Objectresult=addMethod.invoke(invokeTester, newObject[]{newInteger(100),newInteger(200)}); System.out.println((Integer)result);//result为Integer类型 java.lang.Array类提供了动态创建和访问数组元素的各种静态方法。 如代码15-4所示的ArrayTester1类的main()方法创建了一个长度为10的字符串数组,接着把索引位置为5的元素设为"hello",然后再读取索引位置为5的元素的值。 代码15-4ArrayTester1.java importjava.lang.reflect.*; publicclassArrayTester1{ publicstaticvoidmain(Stringargs[])throwsException{ ClassclassType=Class.forName("java.lang.String"); //创建一个长度为10的字符串数组 Objectarray=Array.newInstance(classType,10); //把索引位置为5的元素设为"hello" Array.set(array,5,"hello"); //读取索引位置为5的元素的值 Strings=(String)Array.get(array,5); System.out.println(s); } } 如代码15-5所示的ArrayTester2类的main()方法创建了一个5×10×15的整型数组,并把索引位置为[3][5][10]的元素的值为设37。 代码15-5ArrayTester2.java importjava.lang.reflect.*; publicclassArrayTester2{ publicstaticvoidmain(Stringargs[]){ intdims[]=newint[]{5,10,15}; Objectarray=Array.newInstance(Integer.TYPE,dims); //使arrayObj引用array[3] ObjectarrayObj=Array.get(array,3); Classcls=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); intarrayCast[][][]=(int[][][])array; System.out.println(arrayCast[3][5][10]); } } 15.3在远程方法调用中运用反射机制 假定在SimpleServer服务器端创建了一个HelloServiceImpl对象,它具有getTime()和echo()方法。 HelloServiceImpl类实现了HelloService接口。 如代码15-6和代码15-7所示分别是HelloService接口和HelloServiceImpl类的源程序。 代码15-6HelloService.java packageremotecall; importjava.util.Date; publicinterfaceHelloService{ publicStringecho(Stringmsg); publicDategetTime(); } 代码15-7HelloServiceImpl.java packageremotecall; importjava.util.Date; publicclassHelloServiceImplimplementsHelloService{ publicStringecho(Stringmsg){ return"echo: "+msg; } publicDategetTime(){ returnnewDate(); } } SimpleClient客户端需要把调用的方法名、方法参数类型、方法参数值,以及方法所属的类名或接口名发送给SimpleServer,SimpleServer再调用相关对象的方法,然后把方法的返回值发送给SimpleClient。 为了便于按照面向对象的方式来处理客户端与服务器端的通信,可以把它们发送的信息用Call类(如代码15-8所示)来表示。 一个Call对象表示客户端发起的一个远程调用,它包括调用的类名或接口名、方法名、方法参数类型、方法参数值和方法执行结果。 代码15-8Call.java packageremotecall; importjava.io.*; publicclassCallimplementsSerializable{ privateStringclassName;//表示类名或接口名 privateStringmethodName;//表示方法名 privateClass[]paramTypes;//表示方法参数类型 privateObject[]params;//表示方法参数值 //表示方法的执行结果 //如果方法正常执行,则result为方法返回值,如果方法抛出异常,那么result为该异常。 privateObjectresult; publicCall(){} publicCall(StringclassN
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第十五 Java 反射 机制 正则 表达式
![提示](https://static.bingdoc.com/images/bang_tan.gif)