JAVA中的反射机制对私有成员的访问

来源:互联网 发布:plm编程软件 编辑:程序博客网 时间:2024/05/17 08:52

先讲下原理:

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
Java反射机制主要提供了以下功能: 

在运行时判断任意一个对象所属的类;

在运行时构造任意一个类的对象;

在运行时判断任意一个类所具有的成员变量和方法;

在运行时调用任意一个对象的方法;

生成动态代理。

 

举例子说明如下:

首先我们建立一个测试用的类( TargetClass ):

 

  1. package org.rossalee.test; 
  2. public class TargetClass { 
  3.     public String name ; 
  4.     private String age ; 
  5.     public TargetClass() { 
  6.        super(); 
  7.     } 
  8.     public void showName() { 
  9.        System.out.println(name); 
  10.     } 
  11.     private void showAge() { 
  12.        System.out.println(age); 
  13.     } 

注意其中的age 属性是私有的。

一般来说我们是可以直接操作该类的 name 属性或调用 showName() 方法的。这都是很正常。但如果想要对 age 属性进行设值的话,那就只能依靠 TargeClass 提供一个修饰为 public setAge(String age) 的设值方法,才能进行设值。但我们上面这个类里并没有提供,所以那这个 age 属性基本上是没有办法进行再设值的了。同样,我们也不可以调 TargetClass 类的 shwoAge() 方法。因为他也是 private 的。

 

但我们使用 Java Core API 提供的 Reflect 就可以完成这个功能。

 

实现代码如下:

 

  1. package org.rossalee;
  2. import java.lang.reflect.Field;
  3. import java.lang.reflect.InvocationTargetException;
  4. import java.lang.reflect.Method;
  5. import org.rossalee.test.TargetClass;
  6. public class TestMain {
  7.     public static void main(String[] args) {
  8.         Class clazz = null;
  9.         try {
  10.             clazz = Class.forName("org.rossalee.test.TargetClass");
  11.         } catch (ClassNotFoundException e) {
  12.             e.printStackTrace();
  13.         }
  14.         Field[] f = clazz.getDeclaredFields();
  15.         for (int i = 0; i < f.length; i++) {
  16.             System.out.println("Field " + i + " : " + f[i].getName());
  17.         }
  18.         Method[] m = clazz.getDeclaredMethods();
  19.         for (int i = 0; i < m.length; i++) {
  20.             System.out.println("Method " + i + " : " + m[i].getName());
  21.         }
  22.         TargetClass tc = null;
  23.         try {
  24.             tc = (TargetClass) clazz.newInstance();
  25.         } catch (InstantiationException e) {
  26.             e.printStackTrace();
  27.         } catch (IllegalAccessException e) {
  28.             e.printStackTrace();
  29.         }
  30.         f[1].setAccessible(true);
  31.         try {
  32.             f[1].set(tc, "kenshin");
  33.         } catch (IllegalArgumentException e) {
  34.             e.printStackTrace();
  35.         } catch (IllegalAccessException e) {
  36.             e.printStackTrace();
  37.         }
  38.         m[1].setAccessible(true);
  39.         try {
  40.             m[1].invoke(tc, null);
  41.         } catch (IllegalArgumentException e) {
  42.             e.printStackTrace();
  43.         } catch (IllegalAccessException e) {
  44.             e.printStackTrace();
  45.         } catch (InvocationTargetException e) {
  46.             e.printStackTrace();
  47.         }
  48.     }
  49. }

 

以下是实现对私有属性进行操作的基本步骤:

一、              使用 Class 对象提供的 static 方法 forName() 方法,将类进行加载,成为 Java 里一种特殊的对象——类对象。

 

二、              使用 Class 对象提供的方法 getDeclaredFields() ,此方法   返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。即有公共的也有私有的。

三、              调用对于要进行操作的 field 对象的 setAccessible() 。参数传入“ true ”。此方法从 java.lang.reflect.AccessibleObject 对象中继承而来。执行该方法后,就可以对 age 属性进行操作了。但设值是要有特定的方法来实现的。另外,还有一点要说明的是,此时加载的类对象是没有实例化的,所以最终我们要进行设值的并不是这个类对象,而 TargetClass 类型的对象。这个对象你可以自己 new 出来,也可以通过调用类对象的 newInstance() 方法实例出来。在这里我们暂定这个 new 出来的 TargetClass 对象为 tc ,即:

TargetClass tc=new TargetClass()

四、              这时我们要用 Field 对象提供的 set(Object obj, Object value) 方法进行设置。这个方法有两个参数: obj 就传入我们在一步 new 出来的 tc Value 就传入 age 所属类型的值,这里的 age String 类型,这里传一个 String 进来就可以了。

 

对于私有方法的调用也基本相同,但只是最后使用的是 Method 对象的 invoke(Object obj, Object... args) 方法。 Obj 一样也是 tc args 则是 showAge() 方法的参数,这里是无参的,所以传一个 null 进去就可以了。

 

原创粉丝点击