反射如何拿到私有属性_利用反射私有属性/方法进行设置/调用

因一时兴起看了一些有关 Java反射( Reflection)的东西。以下要说明的问题是如何直接对某个特定类的私有属性( private field)不使用其暴露的 set方法而是直接进行设值操作,或调用类的私有方法( private method)。

首先要说明的是,这在 java里是允许这么做的。虽然这样直接访问私有属性或调用私有方法,会破坏了 OO的一大基本原则:封装,但 Java里是千真万确的提供了这么做的基础的。一些 Open source framework的“豪华”功能也是依赖于此的。

此前在网上看到不少兄弟提出过这样的问题,有人略带讽刺的回复说这样做是不可以的。在这里不才给出一个简单的示例来说明如何完成的这个被看成 Mission Imposable的。

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

packageorg.rossalee.test;

publicclassTargetClass {

publicStringname ;

privateStringage ;

publicTargetClass() {

super();

}

publicvoidshowName() {

System. out.println( name );

}

privatevoidshowAge() {

System. out.println( age );

}

}

这个目标类里有一个 public权限 String类型 “ name” 属性和一个 private权限 String类型的“ age”属性,以及一个 public方法“ showName()”和 private方法“ showAge()”。

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

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

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

一、使用 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 进去就可以了。

实现代码如下:

packageorg.rossalee;

importjava.lang.reflect.Field;

importjava.lang.reflect.InvocationTargetException;

importjava.lang.reflect.Method;

importorg.rossalee.test.TargetClass;

publicclassTestMain {

publicstaticvoidmain(String[] args) {

Class clazz =null;

try{

clazz = Class.forName ( "org.rossalee.test.TargetClass" );

}catch(ClassNotFoundException e) {

e.printStackTrace();

}

Field[] f = clazz.getDeclaredFields();

for( inti = 0; i < f. length ; i++) {

System. out.println( "Field " + i +" : " + f[i].getName());

}

Method[] m = clazz.getDeclaredMethods();

for( inti = 0; i < m. length ; i++) {

System. out.println( "Method " + i +" : " + m[i].getName());

}

TargetClass tc =null;

try{

tc = (TargetClass) clazz.newInstance();

}catch(InstantiationException e) {

e.printStackTrace();

}catch(IllegalAccessException e) {

e.printStackTrace();

}

f[1].setAccessible( true);

try{

f[1].set(tc,"kenshin" );

}catch(IllegalArgumentException e) {

e.printStackTrace();

}catch(IllegalAccessException e) {

e.printStackTrace();

}

m[1].setAccessible( true);

try{

m[1].invoke(tc,null);

}catch(IllegalArgumentException e) {

e.printStackTrace();

}catch(IllegalAccessException e) {

e.printStackTrace();

}catch(InvocationTargetException e) {

e.printStackTrace();

}

}

}

分享到:

18e900b8666ce6f233d25ec02f95ee59.png

72dd548719f0ace4d5f9bca64e1d7715.png

2010-12-03 08:35

浏览 831

分类:非技术

评论

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值