本文链接:http://quentinXXZ.iteye.com/blog/2159052
昨天,一个搞android安全方向的朋友让我帮忙试一下java的反射,要求就是:利用java反射机制获得private class与其它package中default class的实例。这确实是一个比较奇葩的要求,估计也就是android这种平台加上是安全方向的,才常会有这样的需求。
不费话了,众所周知,利用java的反射机制,能做很多java本身限制以外的事情,比方说,获得一个实现的prviate属性或是调用其private的方法,这些都是通过正常使用反射都能实现的。然而标题中的要求,直接使用反射机制,试了很久,确实做不到(能做到的请吱声)。后来,我想的办法,是绕道实现。
比方说,public Class ReflectEntity的实例entiy中有属性为private Class PrivateClass的实例privateClass,我们就可以通过反射获得entiy实例中的privateClass,然后就可以再次通过反射操作privateClass的任何方法与属性。当然这种方法还是有个问题,你必须保证实例entiy实例中的privateClass已经实例化,不为null。
同理,你也可以获得不同package中的default class的实例。
说得差不多了,上代码。
package B:
/**
*
* @author quentinxxz
* @version 2014-11-20 下午4:53:00
*/
package B;
public class ReflectEntity {
private DefaultClass defaultClass = new DefaultClass();
private PrivateClass privateClass = new PrivateClass();
private void print() {
defaultClass.print();
privateClass.print();
}
private class PrivateClass {
public void print() {
System.out.println("this is a method in private class" );
}
}
}
/**
*
* @author quentinxxz.xu
* @version 2014-11-20 下午5:10:51
*/
package B;
class DefaultClass {
public void print() {
System.out.println("this is a method in default class" );
}
}
package A
package A;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import B.ReflectEntity;
/**
*
* @author quentinxxz
* @version 2014-11-20 下午4:50:00
*/
public class TestReflect {
/**
* @param args
* @throws SecurityException
* @throws NoSuchMethodException
* @throws IllegalAccessException
* @throws InstantiationException
* @throws NoSuchFieldException
* @throws InvocationTargetException
* @throws IllegalArgumentException
* @throws ClassNotFoundException
*/
public static void main(String[] args) throws NoSuchMethodException,
SecurityException, InstantiationException, IllegalAccessException,
NoSuchFieldException, ClassNotFoundException,
IllegalArgumentException, InvocationTargetException {
ReflectEntity entity = new ReflectEntity();
Field fieldPrivate = entity.getClass().getDeclaredField("privateClass");
Field fieldDefault = entity.getClass().getDeclaredField("defaultClass");
fieldPrivate.setAccessible(true);
fieldDefault.setAccessible(true);
// System.out.println(fieldPrivate.get(entity).getClass().getDeclaredMethods());
// System.out.println(fieldDefault.get(entity).getClass().getDeclaredMethods());
Method[] methodsInPrivate = fieldPrivate.get(entity).getClass()
.getDeclaredMethods();
Method[] methodsInDefault = fieldDefault.get(entity).getClass()
.getDeclaredMethods();
Method methodInPrivate = methodsInPrivate[0];
methodInPrivate.setAccessible(true);
Method methodInDefault = methodsInDefault[0];
methodInDefault.setAccessible(true);
methodInPrivate.invoke(fieldPrivate.get(entity), new Object[] {});
methodInDefault.invoke(fieldDefault.get(entity), new Object[] {});
}
}