浏览 1878 次
已锁定 主题:java反射学习(转)
该帖已经被评为隐藏帖
|
|
---|---|
作者 | 正文 |
发表时间:2007-12-27
所谓反射,可以理解为在运行时期获取对象类型信息的操作。传统的编程方法要求程序员在编译阶段决定使用的类型,但是在反射的帮助下,编程人员可以动态获取这些信息,从而编写更加具有可移植性的代码。严格地说,反射并非编程语言的特性,因为在任何一种语言都可以实现反射机制,但是如果编程语言本身支持反射,那么反射的实现就会方便很多。 1,获得类型类 我们知道在Java中一切都是对象,我们一般所使用的对象都直接或间接继承自Object类。Object类中包含一个方法名叫getClass,利用这个方法就可以获得一个实例的类型类。类型类指的是代表一个类型的类,因为一切皆是对象,类型也不例外,在Java使用类型类来表示一个类型。所有的类型类都是Class类的实例。例如,有如下一段代码: A a = new A(); if(a.getClass()==A.class) System.out.println("equal"); else System.out.println("unequal"); 可以看到,对象a是A的一个实例,A某一个类,在if语句中使用a.getClass()返回的结果正是A的类型类,在Java中表示一个特定类型的类型类可以用“类型.class”的方式获得,因为a.getClass()获得是A的类型类,也就是A.class,因此上面的代码执行的结果就是打印出 “equal”。特别注意的是,类型类是一一对应的,父类的类型类和子类的类型类是不同的,因此,假设A是B的子类,那么如下的代码将得到 “unequal”的输出: A a = new A(); if(a.getClass()==B.class) System.out.println("equal"); else System.out.println("unequal"); 因此,如果你知道一个实例,那么你可以通过实例的“getClass()”方法获得该对象的类型类,如果你知道一个类型,那么你可以使用“.class”的方法获得该类型的类型类。 2,获得类型的信息 在获得类型类之后,你就可以调用其中的一些方法获得类型的信息了,主要的方法有: getName():String:获得该类型的全称名称。 getSuperClass():Class:获得该类型的直接父类,如果该类型没有直接父类,那么返回null。 getInterfaces():Class[]:获得该类型实现的所有接口。 isArray():boolean:判断该类型是否是数组。 isEnum():boolean:判断该类型是否是枚举类型。 isInterface():boolean:判断该类型是否是接口。 isPrimitive():boolean:判断该类型是否是基本类型,即是否是int,boolean,double等等。 isAssignableFrom(Class cls):boolean:判断这个类型是否是类型cls的父(祖先)类或父(祖先)接口。 getComponentType():Class:如果该类型是一个数组,那么返回该数组的组件类型。 此外还可以进行类型转换这类的操作,主要方法有: asSubclass(Class clazz):Class:将这个类型转换至clazz,如果可以转换,那么总是返回clazz这个引用,否则抛出异常。 cast(Object obj):Object:将obj强制转换为这个类型类代表的类型,不能转换的话将抛出异常。 除了这些以外,利用类型类还可以反射该类型中的所有属性和方法。在Java中所有的属性信息都用Field表示,所有的方法信息都用Method表示,这辆各类都是java.lang.reflect包中的类。在Class中提供了4个相关的方法获得类型的属性: getField(String name):Field getFields():Field[] getDeclaredField(String name):Field getDeclaredFields():Field[] 其中getField用于返回一个指定名称的属性,但是这个属性必须是公有的,这个属性可以在父类中定义。如果是私有属性或者是保护属性,那么都会抛出异常提示找不到这个属性。getFields则是返回类型中的所有公有属性,所有的私有属性和保护属性都找不到。getDeclaredField获得在这个类型的声明中定义的指定名称的属性,这个属性必须是在这个类型的声明中定义,但可以使私有和保护的。getDeclaredFields获得在这个类型的声明中定义的所有属性,包括私有和保护的属性都会被返回,但是所有父类的属性都不会被返回。举个例子,先考虑下面两个类的声明: class A extends B { public int a1; private int a2; } class B { public int b1; private int b2; } 如果利用A的类型类调用getFields,那么会返回a1和b1两个属性,如果调用getField("a2")则会报错;如果调用getDeclaredFields则会返回a1和a2,如果调用getDeclaredField("b1")则会报错。 对于方法也有类似的函数即: getMethods():Method[] getMethod(String name, Class ... parameterTypes):Method getDeclaredMethods():Method[] getDeclaredMethod(Strubg name, Class ...parameterTypes):Method 不定长参数...是JDK5.0以后新加入的语法。这几个方法的用法和上面的类似,只是在获得特定方法时,除了要告知方法的名字,还需要告知方法的参数,如果没有参数,那么可以传递null,或者空数组,但是最好的方法就是什么都不写,编译器会自行解决不定长参数问题。 如果要获得所有的属性(方法),包括公有和私有的,那么就必须利用getDeclareFields(getDeclareMethods)方法,然后再利用getSuperClass的方法获得父类,然后递归下去。 3,属性和方法 所有的属性都使用Field表示,所有的方法都使用Method表示。利用Field和Method可以获得属性和方法的信息,甚至执行是获取、修改属性值和调用方法。 对于属性,主要有以下方法可以使用: getType():Class:获得该属性的类型。 getName():String:获得属性名称。 isAccessible():boolean:判断该属性是否是可以访问的,通常私有和保护的类型都是不可以访问的。 get(Object obj):Object:获得实例obj的属性值,如果该实例的类型中不包含这个属性,那么就会报错。 set(Object obj, Object value):设置该实例的属性值 setAccessible(boolean flag):设置该属性是否可以访问,如果你调用get和set方法,那么有可能会引发访问权限的错误,这个时候你可以调用setAccessible方法使得该属性可以访问。例如下面的代码: A a = new A(); Field f = A.class.getDeclaredField("a2"); f.setAccessibe(true); System.out.println(f.get(a)); f.set(a,12); System.out.println(f.get(a)); 如果移出中间的f.setAccessibe(true);那么代码会报错,反之输出0 12。 对于属性而言,如果该属性的类型是基本类型,那么还可以使用一些便捷的set和get操作,例如getInt,setInt什么的,你可以根据自己的需要调用相应的方法。 对于方法,可以有以下的方法: getName():String:获得方法的名字。 getReturnType():Class:获得方法的返回值类型。 getParameterTypes():Class[]:获得方法的参数类型。 isAccessible():boolean:判断该方法是否是可以访问的。 setAccessible(boolean flag):设置该方法是否可以访问。 invoke(Object obj, Object... args):Object:调用实例obj的相应方法,其参数由args给定,如果没有参数那么可以什么都不写。 getExceptionTypes():Class[]:获得该方法可能抛出的异常类类型。 这几个方法的含义和用法都和Field的类似,这里不再赘述。 4,创建实例 利用Class对象可以创建一个类型的实例。如果一个类型拥有无参数的构造函数,那么可以简单地调用Class.newInstance()方法创建一个实例。如果该类型没有无参数的构造函数,或者你希望是用某个有参数的构造函数,那么可以首先使用getConstructors()、 getConstructor(Class[] parameterTypes)和getDeclaredConstructors()、getDeclaredConstructor(Class[] parameterTypes)获得构造函数,这两个方法的返回值都使Constructor类型。特别注意的是,构造函数不能继承,因此你调用 getConstructor也只能返回这个类型中定义的所有公有构造函数。 Constructor的使用方法和Method的类似,它也存在getParameterTypes()方法和getExceptionTypes() 方法,不同的是,它使用newInstance(Object... args)来调用一个构造函数,注意newInstance不需要实例对象,因为这个时候你还没创建出来这个实例呢。[size=18][/size][/color][color=red] 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |