java 用反射实现类外访问类的私有成员
学习本文需要提前掌握的知识:java类与对象
1、 思路分析
想要实现访问类的私有成员,我们有两个思路,一个是将私有成员转换成公有成员,另一个思路是在访问私有成员的时候绕过java语言检测。
第一个思路,将私有成员转换成公有成员:这就和我们平常获取类的私有属性所用的方法一致——为这个私有成员写一个公有的get方法。
public void getInformation(){
return 私有变量名;
}
public void carryFuntion(){
私有方法;
}
像上面这样即可访问类的私有属性和方法,但这种方法需要在原类的基础上修改。来看下第二种方法,绕过java语言检测,这需要用到新的java知识——反射。
2、 java反射——另一种对象实现的方法
(1)、Class类:Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象。
此类的部分相关方法:
forName(String className) //返回与带有给定字符串名的类或接口相关联的 Class 对象,className为所需类的完全限定名。
getConstructor() //获取当前对象的构造函数
getMethod(String name) //获取此类的公有方法,name为方法名,后面可以放此方法的参数
getDeclaredMethod(String name) //获取此类的所有方法,name为方法名,后面可以放此方法的参数
(2)、Constructor类:提供关于类的单个构造方法的信息以及对它的访问权限。
此类的部分相关方法:
newInstance() //调用此对象的构造函数创建对象
(3)、Method类:提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。
此类的部分相关方法:
//将此对象的 accessible 标志设置为指示的布尔值。值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。值为 false 则指示反射的对象应该实施 Java 语言访问检查。
mPrivate.setAccessible(Boolean flag);
//执行该方法,obj为从中调用底层方法的对象,args为用于方法调用的参数。
invoke(Object obj, Object... args)
3、使用反射绕过java语言检测
首先创建一个对象
public class Try{
private void privateTest(){
System.out.println("这是role对象的私有方法");
}
public void publicTest(){
System.out.println("这是role对象的公有方法");
}
}
在主函数里写一个方法,先获取相关对象,然后获取其构造函数,执行构造函数创建对象,获取此对象的相关方法(如果该方法是非公有方法需要用getDeclaredMethod方法获取),非公有方法需要用setAccessible绕过java语言检测,最后执行这些方法即可。
public static void testMethod() throws Exception {
// forName返回与带有给定字符串名的类或接口相关联的Class对象。
Class s =
Class.forName("com.antony.inherit0726.Try");
/*
* 返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。参数是 Class 对象的一个数组,这些
* Class 对象按声明顺序标识构造方法的形参类型。
*/
Constructor con = s.getConstructor();
// 创建对象
Object obj = con.newInstance(null);
// 获取类的方法
Method mPublic = s.getMethod("publicTest");
// 可以获取所有方法
Method mPrivate = s.getDeclaredMethod("privateTest");
/*
* 将此对象的 accessible 标志设置为指示的布尔值。值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。值为false 则指示反射的对象应该实施 java语言访问检查。
*/
mPrivate.setAccessible(true);
// 调用方法
mPublic.invoke(obj);
mPrivate.invoke(obj);
}