浅谈Java反射机制

反射库(reflection library )提供了一个功能强大的工具集,一遍编写可以动态操纵java代码的程序。这种功能被大量用在javaBeans中(java组件的体系结构)。使用反射,java可以支持vb用户习惯使用的工具,特别是在设计或运行时添加新类时,可以快速应用开发工具动态查询新添加类的能力。

能够分析类能力的程序称为反射(refletive)。反射机制可以用来:

l  在运行时分析类的能力

l  在运行时查看对象,例如编写toString方法供所有类使用。

l  实现通用的数组操作代码

l  利用method对象,该对象很像C++中的函数指针

1.Class类

在程序运行期间java运行时系统始终未所有的对象维护一个被称为运行时的类型标识。这个信息跟踪着每个对象所属的类。虚拟机利用运行时类型信息选择相应的方法执行。

我们可以通过专门的java类来访问这些信息。保存这些信息的类被称为Class,Object类中的getClass方法会返回一个Class类型的实例(即返回该对象所属的类,包括包名)。

例如 Employee  e=null;

        Class c1=e.getClass();

        String name=c1.getName();

将会打印出 Employee

还可以通过Class的静态方法forName获得类名对应的Class对象

        String className=”java.util.Random”;

        Class c1=Class.forName(className);

获得Class类对象的第三种方法:如果T是任意的java类型(或void关键字),T.class将代表匹配的类对象

Class c1=Random.class;//假设java.uitl.Random类已导入

Class c2=int.class;

Class c3=Double[].class;

注意:一个Class对象实际表示一个类型,而这个类型不一定是一种类,int不是类,但int.class是一个Class类型的对象

            虚拟机为每个类型管理一个Class对象,因此可以用==运算符实现两个类对象比较操作:

例如if(e.getClass()==Employee.class)…

             还有一个很有用的方法newInstance,可以动态创建一个类的实例,例如:

           Employee eCopy= e.getClass().newInstance();

      创建了一个与e具有相同类类型的实例,newInstance方法调用默认的构造器初始化新创建的对象,如果该类没有摩恩构造器会抛出异常

String s=”java.util.Random”;

Object o=Class.forName(s).newInstance();

如果需要一个有参构造对象,必须用Constructor类中的newInstance方法了

2利用反射的分析类的能力

         反射机制最重要的内容—检查类的结构

         在java.lang.reflect包中有三个类:Field,Method,Constructor分别用于描述类的域,方法和构造器,这三个类都有一个叫做getName方法,用来返回项目的名称。Field有个getType方法返回描述域所属类型的Class对象。Method和Constructor类有能够报告参数类型的方法,Method类还可以有能报告返回类型的方法,这三个类还有一个叫做getModifiers的方法,它将返回一个整形数值,用不同的位开关描述public和static这样的修饰符使用状况,另外,还可以利用java.lang.reflect包中的Modifier类的静态方法分析getModifiers返回的整数数值。例如可以使用Modifier类中的isPublic,isPrivate或isFinal判断方法或构造器是否是public,private,final。我们需要做的uanu工作就是要调用Modifier类的相关方法,对返回的整型数值进行发内心。另外还可以利用Modifier.toString 方法将修饰符打印出来

         Class类中的getFields,getMethods和getConstructors方法将分别返回类提供的public域,方法和构造器数组,其中包括超类的宫欧处呢雇员。Class类的getDeclaredFields,getDeclaredMethods和getDeclaredConstructors方法将分别返回类中声明的全部域,方法和构造器,其中包括私有和受保护的成员,但不包括超类的成员

     3在运行时使用反射分析对象

前一节知道如何查看任意对象的数据域名称和类型:

l  获取对应的Class对象

l  通过Class对象调用getDeclaredFields

本节进一步查看数据域的实际内容,利用反射机制可以查看在编译时还不清楚的对象域。

查看对象域的关键方法是Field类中的get方法,如果f是一个Field类型的对象,object是某个包含f域的类的对象,f.get(obj)将返回一个对象,其值为obj域的当前值

Employee  harry=new Employee(“harry_potter”,3500,1,12,1998);

Class c1=harry.getClass();

Field f=c1.getDeclaredField(“name”);

Object v=f.get(harry);

有两个问题:

①  对象域中某个属性的访问权限如果不是public如何获取值

②  属性的类型如果不是引用类型而是基本数据类型如何获取

问题①,如果属性是私有域或者保护域,会抛出IllegalAccessException异常,只有利用该属性的get方法才可以访问到属性值。除非拥有访问权限,否则java安全机制只允许查看任意对象有哪些域,而不允许读取他们的值。

         反射机制的默认行为受限于java访问控制。然而,如果一个java程序没有受到安全管理器控制,就可以覆盖访问控制。可以调用Method,Constructor,Field对象的setAcessible方法:

         f.setAccessible(true);

Object v=f.get(harry);//now is OK

setAccessible 方法是AccessibleObject类中的一个方法,他是Filed,Method,Constructor类的公共超类,这个特性是为了调试,持久存储和相似机制提供的。

问题②对于非引用类型的属性,可以调用相应的getInt,getDouble等对应方法返回基本类型的类型值,也可以直接用get方法,此时返回的是数据类型的包装类型。

double salary=f.getDouble(harry);//ok

Double salary=f.get(harry);//ok

         当然,可以获得就可以设置,调用相应的f.set(obj,value)可以将obj对象的f域设置为新值

4使用反射编写泛型数组代码

Java.lang.reflect包中的Array类允许动态创建数组,例如,可以将这个特性应用到Array类中的copyOf方法实现中,可以扩展已经填满的数组

posted @ 2018-01-23 14:18  聊寂园  阅读(240)  评论(0编辑  收藏  举报