反射
能够分析类能力的程序成为反射
反射可以用来
- 在运行时分析类的能力
- 在运行时查看对象,例如,编写一个toString方法来供所有类使用
- 实现通用的数组操作代码
- 利用Method对象,这个对象很像C++中的函数指针
Object 类中的 getClass ( ) 方法将会返回一个 Class 类型的实例。 最常用的Class 方法是 getName。 这个方法将返回类的名字 。 例如 , 下面这条语句 :
System.out.println(e.getClass ( ).getName ( ) + " " +e.getNameO) ;
如果类在一个包里,包的名字也作为类名的一部分
还可以调用静态方法 forName 获得类名对应的 Class 对象。
String dassName = " java . util . Random " ;
Class cl = Cl ass . forName ( dassName ) ;
如果类名保存在字符串中,并可在运行中改变,就可以使用这个方法。当然,这个方法只有在 dassName 是类名或接口名时才能够执行。否则,forName 方法将抛出一个checkedexception ( 已检查异常 )。 无论何时使用这个方法 ,都应该提供一个异常处理器 ( exceptionhandler )
虚拟机为每个类型管理一个 Class 对象 。 因此 , 可以利用 = 运算符实现两个类对象比较的操作 。 例如,
if ( e.getClass() == Employee.class ) . . .
还有一个很有用的方法 newlnstance ( ), 可以用来动态地创建一个类的实例,如:
e . getClass 0 . newlnstance ( )
创建了一个与 e 具有相同类类型的实例 。 newlnstance 方法调用默认的构造器 ( 没有参数的构造器 ) 初始化新创建的对象 。 如果这个类没有默认的构造器 , 就会抛出一个异常 。
将 forName 与 newlnstance 配合起来使用 , 可以根据存储在字符串中的类名创建一个对象
String s = " java . util . Random " ;
Object m = Class.forName (s).newlnstance ( )
在 java . lang . reflect 包中有三个类 Field、 Method 和Constructor 分别用于描述类的域 、 方法和构造器 。 这三个类都有一个叫做 getName 的方法 , 用来返回项目的名称。 Held 类有一个 getType 方法 , 用来返回描述域所属类型的 Class 对象。 Method 和 Constructor 类有能够报告参数类型的方法, Method 类还有一个可以报告返回类型的方法 。 这 < 个类还有一个叫做 getModifiers 的方法 , 它将返回一个整型数值, 用不同的位开关描述 public 和 static 这样的修饰符使用状况。 另外 , 还可以利用 java . lang . refleCt 包中的Modifiei • 类的静态方法分析getModifiers 返回的整型数值 。 例如 , 可以使用 Modifier 类中的 isPublic 、 isPrivate 或isFinal判断方法或构造器是否是 public 、 private 或 final 。 我们需要做的全部工作就是调用 Modifier类的相应方法, 并对返回的整型数值进行分析 , 另外 , 还可以利用 Modifier . toString 方法将修饰符打印出来
Class 类中的 getFields、 getMethods 和 getConstructors 方 法 将 分 别 返 回 类 提 供 的public 域 、 方法和构造器数组 , 其中包括超类的公有成员 。 Class 类的 getDeclareFields、getDeclareMethods 和getDeclared-Constructors 方法将分别返回类中声明的全部域 、 方法和构造器 , 其中包括私有和受保护成员, 但不包括超类的成员 。
Class cl = Class.forName(name);
Class supercl = cl.getSuperClass();
String modifiers = Modifier.toString(cl.getModifiers());//获取修饰符
通过反射分析对象
- 获得对应的Class对象
- 通过Class对象调用getDeclaredFields
查看对象域的关键方法是 Field 类中的 get 方法。 如果 f 是一个Field 类型的对象 ( 例如,通过 getDeclaredFields 得到的对象 ), obj是某个包含 f 域的类的对象,f . get ( obj ) 将返回一个对象, 其值为 obj域的当前值 。 这样说起来显得有点抽象, 这里看一看下面这个示例的运行 。
Employee harry = new Employee ( " Harry Hacker " , 35000 , 10 , 1 , 1989 ) ;
Class cl = harry . getClass 0 ;
// the class object representing Employee
Field f = cl . getDeclaredFieldC ' name " ) :
// the name field of the Employee class
Object v = f . get ( harry ) ;
// the value of the name field of the harry object , i . e . , the String object " Harry Hacker "
实际上, 这段代码存在一个问题 。 由于 name 是一个私有域 ,
所以 get 方法将会抛出一个IllegalAccessException。 只有利用 get 方法才能得到可访问域的值 。 除非拥有访问权限 , 否则Java 安全机制只允许査看任意对象有哪些域 , 而不允许读取它们的值
。反射机制的默认行为受限于 Java 的访问控制 。 然而,如果一个 Java 程序没有受到安全管理器的控制 , 就可以覆盖访问控制 。 为了达到这个目的 , 需要调用 Field、 Method 或Constructor 对象的 setAccessible 方法。 例如 ,
f.setAtcessible ( true ) ; / / now OK to call f . get ( harry ) ;
setAccessible 方法是 AccessibleObject 类中的一个方法 , 它是 Field 、 Method 和 Constructor类的公共超类。 这个特性是为调试 、 持久存储和相似机制提供的 。