利用反射对私有属性/方法进行设置/调用
2011-03-10 08:32
543 查看
因一时兴起看了一些有关 Java 反射( Reflection )的东西。以下要说明的问题是如何直接对某个特定类的私有属性( private field )不使用其暴露的 set 方法而是直接进行设值操作,或调用类的私有方法( private method )。
首先要说明的是,这在 java 里是允许这么做的。虽然这样直接访问私有属性或调用私有方法,会破坏了 OO 的一大基本原则:封装,但 Java 里是千真万确的提供了这么做的基础的。一些 Open source framework 的“豪华”功能也是依赖于此的。
此前在网上看到不少兄弟提出过这样的问题,有人略带讽刺的回复说这样做是不可以的。在这里不才给出一个简单的示例来说明如何完成的这个被看成 Mission Imposable 的。
首先我们建立一个测试用的类( TargetClass):
这个目标类里有一个 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 对象的 setAccessible() 。参数传入“ true ”。此方法从 java.lang.reflect.AccessibleObject 对象中继承而来。执行该方法后,就可以对 age 属性进行操作了。但设值是要有特定的方法来实现的。另外,还有一点要说明的是,此时加载的类对象是没有实例化的,所以最终我们要进行设值的并不是这个类对象,而 TargetClass类型的对象。这个对象你可以自己 new 出来,也可以通过调用类对象的 newInstance() 方法实例出来。在这里我们暂定这个 new 出来的 TargetClass对象为 tc ,即:
TargetClasstc=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 进去就可以了。
实现代码如下:
代码2:
首先要说明的是,这在 java 里是允许这么做的。虽然这样直接访问私有属性或调用私有方法,会破坏了 OO 的一大基本原则:封装,但 Java 里是千真万确的提供了这么做的基础的。一些 Open source framework 的“豪华”功能也是依赖于此的。
此前在网上看到不少兄弟提出过这样的问题,有人略带讽刺的回复说这样做是不可以的。在这里不才给出一个简单的示例来说明如何完成的这个被看成 Mission Imposable 的。
首先我们建立一个测试用的类( TargetClass):
package org.rossalee.test; public class TargetClass{ public String name ; private String age ; public TargetClass() { super (); } public void showName() { System. out .println( name ); } private void showAge() { 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 ,即:
TargetClasstc=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 进去就可以了。
实现代码如下:
package org.rossalee;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.rossalee.test.TargetClass;
public class TestMain {
public static void main(String[] args) {
Classclazz = null ;
try {
clazz = Class.forName ( "org.rossalee.test.TargetClass" );
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Field[] f = clazz.getDeclaredFields();
for ( int i = 0; i < f. length ; i++) {
System. out .println( "Field" + i + " : " + f[i].getName());
}
Method[] m = clazz.getDeclaredMethods();
for ( int i = 0; i < m. length ; i++) {
System. out .println( "Method " + i + " : " + m[i].getName());
}
TargetClasstc = 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();
}
}
}
代码2:
public static void main(String[] args) throws SecurityException, ClassNotFoundException, IllegalArgumentException, IllegalAccessException { CCC obj = new CCC(); obj.setName("name value"); obj.setCode("code value"); Field[] fds = Class.forName(obj.getClass().getName()).getDeclaredFields(); System.out.println(fds.length); for(int i=0;i<fds.length;i++) { System.out.println(fds[i].getName()); fds[i].setAccessible(true); System.out.println(fds[i].get(obj)); } }
相关文章推荐
- 利用反射对私有属性/方法进行设置/调用(转自己贴)
- Java记录 -88- 利用反射机制调用对象的私有方法和属性
- 利用反射调用私有方法、访问私有属性
- 利用java的反射机制调用类的私有方法及私有属性
- 利用反射访问私有属性、调用私有方法
- Java记录 -88- 利用反射机制调用对象的私有方法和属性
- 通过反射创建私有化类的对象,调用类的私有方法,改变私有属性
- Java反射学习总结二(用反射调用对象的私有属性和方法)
- 对对象类型和调用方法属性进行存储以提升反射性能
- 利用GetType反射方法再调用方法进行传递参数实现调用
- java反射调用私有方法和修改私有属性
- C#反射新建类实例和调用类方法及属性帮助类 以及获取或设置对象属性中字段值帮助类
- 利用反射调用类及其属性和方法
- 关于java的反射,调用私有方法(有参数私有方法),私有属性
- 使用反射调用私有属性和方法
- 反射系列之属性方法(调用私有方法,获得属性值)
- java利用反射访问类的私有(private)属性及方法
- Java反射高级应用--利用反射调用类的私有方法修改私有方法值,以及替换Java的类成员数据
- 对对象类型和调用方法属性进行存储以提升反射性能
- 转:用反射调用对象的私有属性和方法(经典)