java(教学0)韩建雷 java反射机制_relea.ppt_第1页
java(教学0)韩建雷 java反射机制_relea.ppt_第2页
java(教学0)韩建雷 java反射机制_relea.ppt_第3页
java(教学0)韩建雷 java反射机制_relea.ppt_第4页
java(教学0)韩建雷 java反射机制_relea.ppt_第5页
已阅读5页,还剩32页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

JAVA反射机制,议程,概述 主要功能 分析类 取得Class 对象 取得类名 找出超类 确定某类实现的接口 检查接口 取得类字段 取得构造方法 取得方法信息 取得字段的值 创建对象,概述,在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法?答案是肯定的。这种动态获取类的信息以及动态调用对象的方法的功能来自于Java 语言的反射(Reflection)机制。 Reflection是一系列的API,它用于表示或者处理当前JVM中的类,接口和对象。,主要功能,确定一个对象的类 取出类的modifiers,数据成员,方法,构造器和超类 找出某个接口里定义的常量和方法说明 创建一个类实例,这个实例在运行时刻才有名字(运行时间才生成的对象) 取得和设定对象数据成员的值,如果数据成员名是运行时刻确定的也能做倒。 在运行时刻调用动态对象的方法 创建数组,数组大小和类型在运行时刻才确定。也能更改数组成员的值。,分析类,如果你在编一个类浏览器程序,你就需要取得类在运行时刻的有关信息。比如,你想显示某个类的数据成员名,方法和构造器。再比如,你想显示某个类到底实现了哪些接口。这些信息可以由自省此类的Class对象来取得。 对于每个类而言,JRE都为其保留一个不变的Class类型的对象。一个Class对象包含了特定某个类的有关信息。你可以通过调用Class对象的有关方法,返回特定类的构造器对象,方法对象和数据成员对象。通过这些返回的对象,你就可以得到构造器,方法和数据成员的所有详细原始定义。 Class对象也包含接口信息。你可以调用Class对象的某些方法来取得某接口的modifiers,方法和公共常数。如果Class对象用来表示接口,那么Class对象的部份方法就不可用。比如getConstructors,接口根本没构造器,所以这个方法就没用。,取得Class对象,如果可以取得某个类的实例,你可以调用Ojbect.getClass方法。 请看例子: mystery是某个类的对象。 Class c = mystery.getClass(); 类对象c可以直接输出,请看 JButton jb=new JButton(); Class mc= jb.getClass() ; System.err.println(“类内容“+mc.toString() ); 如果你想取得某个类对象的超类,可以用getSuperclass方法。本例中,getSuperclass方法返回TextComponent的Class对象,因为TextComponet类是TextField的超类。 TextField t = new TextField(); Class c = t.getClass(); Class s = c.getSuperclass(); 运行后直接输出c和s的结果是: 本类内容class javax.swing.JTextField 超类内容class javax.swing.text.JTextComponent,如果你知道类在编译时的名字(类名),取出它的class对象就简单了:类名后跟“.class”后缀就行了。如: Class c1 = java.awt.Button.class; System.err.println(“本类内容+c1.toString() ); 有时候,在编译的时候,对象属于哪个类,类名不知道(多态性),但是在运行的时候就知道对象属于哪个类了(运行时刻绑定)。这时候运行时刻取得对象的类就应该用forName方法。在下例中,如果字串变量strg内容是”java.awt.Button”,那么用forName方法返回Button的Class 对象。 如:,String strg=“java.awt.Button“; Class c2; c2=null; try c2= Class.forName(strg) ; catch(ClassNotFoundException e) System.err.println(“没有这个类“); System.exit(1); System.err.println(“forName 内容“+c2.toString() );,取得类名,每个类都有类名,比如下面的类名就是Point public class Point int x, y; 在运行时刻,类名可以调用Class对象的getName方法来取得。getName返回一个字串,字串是完整的类名。 下面举例:例子首先取得对象的Class对象,然后调用getName得到类名。,import java.lang.reflect.*; import java.awt.*; class SampleName public static void main(String args) Button b = new Button(); printName(b); static void printName(Object o) Class c = o.getClass(); String s = c.getName(); System.out.println(s); 程序输出java.awt.Button,显示类描述符 什么是类描述符呢?就是public, abstract, 或者final. 类描述符前面就是class关键字,请看例子: 要在运行时刻知道类描述符得做以下两步工作: 调用Class对象的getModifiers方法取得描述符用isPublic, isAbstract, and isFinal判断各个描述符 请大家看例子。,import java.lang.reflect.*; import java.awt.*; class SampleModifier public static void main(String args) String s = new String(); printModifiers(s); public static void printModifiers(Object o) Class c = o.getClass(); int m = c.getModifiers(); if (Modifier.isPublic(m) System.out.println(“public“); if (Modifier.isAbstract(m) System.out.println(“abstract“); if (Modifier.isFinal(m) System.out.println(“final“); 从这个程序运行结果中看到String 类是public和final的。,找出超类,java的类是有继承结构的,如果你想编一个类浏览程序,取得超类这一功能当然需要。 用getSuperclass方法可以做到。这个方法返回超类的class对象,如果某类没有超类就返回null.如果想找某个类的父类的父类的。那你可以反复调用getSuperclass直到返回null,import java.lang.reflect.*; import java.awt.*; class SampleSuper public static void main(String args) Button b = new Button(); printSuperclasses(b); static void printSuperclasses(Object o) Class subclass = o.getClass(); Class superclass = subclass.getSuperclass(); while (superclass != null) String className = superclass.getName(); System.out.println(className); subclass = superclass; superclass = subclass.getSuperclass(); 程序输出如下: java.awt.Component java.lang.Object,确定某类实现的接口,一个对象的类型不仅仅由它的类和超类决定,还有一个重要因素是其接口。接口用implements说明,比如: public class RandomAccessFile implements DataOutput, DataInput 要知道一个类实现多少接口可以调用getInterface方法。此方法返回一个Class对象数组。每个元素都代表此类实现的一个接口。用某个元素的getName方法可以取得接口的名字。 下面的程序打印出RandomAccessFile类实现的所有接口,import java.lang.reflect.*; import java.io.*; class SampleInterface public static void main(String args) try RandomAccessFile r = new RandomAccessFile(“myfile“, “r“); printInterfaceNames(r); catch (IOException e) System.out.println(e); static void printInterfaceNames(Object o) Class c = o.getClass(); Class theInterfaces = c.getInterfaces(); for (int i = 0; i theInterfaces.length; i+) String interfaceName = theInterfacesi.getName(); System.out.println(interfaceName); Note that the interface names printed by the sample program are fully qualified: java.io.DataOutput java.io.DataInput,检查接口,对象即可以表示接口也可以表示类。如果你搞不清一个对象到底是由接口来的还是由类来的,可以用isInterface 方法来确定。 要得到接口的信息可以用Class类的方法。如果要找接口中的public常量,可以用getFields方法。用getMethods 可以取得接口中的方法。要看接口的修饰符,可以用getModifiers方法。 下面程序调用isInterface来确定Observer是一个接口,Observale是一个类。,import java.lang.reflect.*; import java.util.*; /*说明如何判断一个对象是接口还是对象实现的*/ class SampleCheckInterface public static void main(String args) Class observer = Observer.class; Class observable = Observable.class; Class jb=java.awt.Button.class ; verifyInterface(observer); verifyInterface(observable); verifyInterface(jb); static void verifyInterface(Class c) String name = c.getName(); if (c.isInterface() System.out.println(name + “ 是接口.“); else System.out.println(name + “ 是类.“); 程序的输出是java.util.Observer是接口.java.util.Observable 是类. java.awt.Button 是类.,取得类字段,写个程序显示类的名字和所有方法和数据成员,调用Class对象的getFields方法就行了。这个方法返回一个字段对象(Field对象数组)数组,一个对象对应一个字段。 如果某个公共字段属于下列情况之一,它就可以被用户存取到 属于本类或超类 本类实现的接口 本类的接口的接口。 由Field对象提供的方法允许你取得字段的名字,类型和描述符。你甚至可以给字段赋值或者取字段的值。 下面的例子打印了panel类的成员的名字和类型。注意,取成员用了getFields方法,用Field对象的getName取名字,用getType取得某个成员的Class对象,由此判断它的 类型。,import java.lang.reflect.*; import java.awt.*; class SampleField public static void main(String args) Panel g = new Panel (); printFieldNames(g); static void printFieldNames(Object o) Class c = o.getClass(); Field publicFields = c.getFields(); for (int i = 0; i publicFields.length; i+) String fieldName = publicFieldsi.getName(); Class typeClass = publicFieldsi.getType(); String fieldType = typeClass.getName(); System.out.println(“字段名: “ + fieldName +“, 类型: “ + fieldType); ,如果一个类的字段是另一个类对象,输出又会如何呢?请看SampleClassField.java import java.lang.reflect.*; public class SampleClassField public int i=0; public float f=0; public Member mb=new Member(“Sam“); public SampleClassField() System.err.println(“start“); public static void main(String args) SampleClassField sampleClassField1 = new SampleClassField(); printFieldNames(sampleClassField1) ; public static void printFieldNames(Object o) Class c = o.getClass(); Field publicFields = c.getFields(); for (int i = 0; i publicFields.length; i+) String fieldName = publicFieldsi.getName(); Class typeClass = publicFieldsi.getType(); String fieldType = typeClass.getName(); System.out.println(“字段名: “+fieldName+“, 类型: “ +fieldType); class Member private String name; public Member(String n1) name=n1; public String getMember() return name; 大家可以看到,类成员是一个对象程序也能输出package名.类名,取得构造方法,构造方法是在创建类对象时调用的特殊方法,构造方法可以重载,由它们的参数加以区别 调用getConstructors方法可以取得类构造方法的有关信息。这个方法返回一个数组的Constructor对象。你可以用Constructor对象里的相关方法来确定构造方法的名字,描述符,参数类型和抛出的意外列表。你也可以用Constructor.newInstance创建一个新的Constructor对象 下面的例子程序打印出Rectangle类的每个构造方法的参数表,程序是这样执行的。 程序用getConstructors方法取得一个数组的Constructor 对象,对于在Constructor数组的每个元素,都调用getParameterTypes方法建了一个数组的Class对象,这个数组里放了某一个构造方法的参数类型表。程序调用getName取得每个参数的类名。,import java.lang.reflect.*; import java.awt.*; class SampleConstructor public static void main(String args) Rectangle r = new Rectangle(); showConstructors(r); static void showConstructors(Object o) Class c = o.getClass(); Constructor theConstructors = c.getConstructors(); for (int i = 0; i theConstructors.length; i+) System.out.print(“( “); Class parameterTypes=theConstructorsi.getParameterTypes(); for (int k = 0;k parameterTypes.length; k +) String parameterString = parameterTypesk.getName(); System.out.print(parameterString + “ “); System.out.println(“)“); ,取得方法信息,如何找出类的public方法呢?当然是调用getMethods方法。由getMethods方法返回一个数组,数组元素类型是Method对象。方法的名字,类型,参数,描述和抛出的意外都可以由Method对象的方法来取得。用Method.invoke 方法自己调用这个方法。 下面的例子打印Polygon类里的公共方法的名字、返回类型,参数类型。它用getMethods方法取出方法对象数组对于Method数组的每个元素做以下事情: getName取方法名 getReturnType取返回值的类型 用getParameterTypes取得返回类型的数组 对每个参数用getName取参数名。,import java.lang.reflect.*; import java.awt.*; class SampleMethod public static void main(String args) Polygon p = new Polygon(); showMethods(p); static void showMethods(Object o) Class c = o.getClass(); Method theMethods = c.getMethods(); for (int i = 0; i theMethods.length; i+) String methodString = theMethodsi.getName(); System.out.println(“Name: “ + methodString); String returnString=theMethodsi.getReturnType().getName(); System.out.println(“ Return Type: “ + returnString); Class parameterTypes = theMethodsi.getParameterTypes(); System.out.print(“ Parameter Types:“); for (int k = 0; k parameterTypes.length; k +) String parameterString = parameterTypesk.getName(); System.out.print(“ “ + parameterString); System.out.println(); ,创建对象,如果在编译时你不知道类名,你怎么在运行的时候创建一个对象?如果你在运行时候才知道类名,然后想新建一个对象怎么办?比如用户在设计器里拖了一个部件向屏幕上一放,这时候怎么办? String className; Object o = new (className); /这么做不对! new 操作符不能这么用。 如果你要建立一个对象,用不着构造参数,那么,你可以用Class对象的newInstance 建立之。问题是如果此类没有无参构造方法怎么办呢?就扔出了NoSuchMethodException意外。构造的信息可以从getConstructors中得到。 下面的程序先用forName找到类,然后用newInstance建立一个对象。,import java.lang.reflect.*; import java.awt.*; class SampleNoArg public static void main(String args) Rectangle r = (Rectangle)createObject(“Rectangle“); System.out.println(r.toString(); static Object createObject(String className) Object object = null; try Class classDefinition = Class.forName(className); object = classDefinition.newInstance(); catch(InstantiationException e)System.out.println(e); catch(IllegalAccessException e) System.out.println(e); catch(ClassNotFoundException e) System.out.println(e); return object; ,如果构造有参数咋办呢?那你就用Constructor对象的newInstance方法,而不是Class对象的方法。具体按以下步骤做: 用Class对象的getConstructor方法取得Constructor对象数组。getConstructor方法带一个参数,它是一个数组,里面放的是所需要构造方法参数的个数和类型。 用Constructor的newInstance方法创建对象。它有一个参数:一个对象数组,其元素就是要传给构造方法的参数表 下面的例子创建了两个integer参数的一个Rectangle对象 相当于Rectangle rectangle = new Rectangle(12, 34); 传给newInstance的数组元素是object类型,所以呢,基本类型得包装一下Wrapped.,import java.lang.reflect.*; import java.awt.*; class SampleInstance public static void main(String args) Rectangle rectangle; Class rectangleDefinition; Class intArgsClass = new Class int.class, int.class; Integer height = new Integer(12); Integer width = new Integer(34); Object intArgs = new Object height, width; Constructor intArgsConstructor; try rectangleDefinition = Class.forName(“java.awt.Rectangle“); intArgsConstructor=rectangleDefinition.getConstructor(intArgsClass); rectangle = (Rectangle) createObject(intArgsConstructor, intArgs); catch(ClassNotFoundException e)System.out.println(e); catch(NoSuchMethodException e)System.out.println(e); ,public static Object createObject(Constructor constructor,Object arguments) System.out.println (“Constructor: “ + constructor.toString(); Object object = null; try object = constructor.newInstance(arguments); System.out.println (“Object: “ + object.toString(); return object; catch(InstantiationException e) System.out.println(e); catch(IllegalAccessException e) System.out.println(e); catch(IllegalArgumentException e) System.out.println(e); catch(InvocationTargetException e) System.out.println(e); return object; 程序输出: Constructor: public java.awt.Rectangle(int,int) Object: java.awt.Rectanglex=0,y=0,width=12,height=34,取得字段的值,如果你开发debugger,运行时候取对象字段的值当然得会编程序。按三步走: 1 创建一个Class对象。 2 用getField方法创建一个Field对象 3 调用某个Field对象的的get方法 Fields类有专门的方法对付基本数据类型。比如getInt,getFloat等等,顾名思义就成了。如果是对象的话就好办了,直接用get方法返回对象。 下面的程序取的是height字段。height是个基本数据类型int,返回的就是个wapper对象。field是在编译时知道名字的字段,但是,在GUI设计器等动态的东西中,字段名在运行时候才知道。,import java.lang.reflect.*; import java.awt.*; class SampleGet public static void main(String args) Rectangle r = new Rectangle(100, 325); printHeight(r); static void printHeight(Rectangle r) Field heightField; Integer heightValue; Class c = r.getClass(); try heightField = c.getField(“height“); heightValue = (Integer) heightField.get(r);/用getInt 也可以 System.out.println(“Height: “ + heightValue.toString(); catch(NoSuchFieldException e) System.out.println(e); catch(SecurityException e) System.out.println(e); catch(IllegalAccessException e) System.out.println(e); ,设定字段值 一些调试器允许用户在调试期间改变字段值。如果你在写这样的程序,就得照下面的步骤做: 1 先建一个Class对象 2 用getField对象的getField方法取得Field对象。 3 调用Field对象的合适的set方法。 Field类提供了setBoolean,setInt等方法。如果字段是对象,直接用set方法就行了。对于原始类型对象,用wrapper也行。 下面的程序修改了width字段。,import java.lang.reflect.*; import java.awt.*; class SampleSet public static void main(String args) Rectangle r = new Rectangle(100, 20); System.out.println(“original: “ + r.toString(); modifyWidth(r, new Integer(300); System.out.println(“modified: “ + r.toString(); static void modifyWidth(Rectangle r, Integer widthParam ) Field widthField; Integer widthValue; Class c = r.get

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论