大家都知道private变量是无法访问的,一编译就报错根本无法访问啊。本文教你如何破解这种限制。
实现的原理是利用了Java的反射机制。
首先定义一个最简单的类,只有一个私有变量和一个公开的方法。代码如下:
class Foo {
private String message = "This is a Foo.";
public void show() {
System.out.println(message);
}
}
正常情况下调用show函数会输出“This is a Foo.”。下面这段代码通过setAccessible方法绕过了Java的权限检测。
Class<Foo> fooClass = (Class<Foo>) foo.getClass();
Field messageField = fooClass.getDeclaredField("message");
messageField.setAccessible(true); // 绕过权限检测!
setAccessble接受一个布尔类型的参数,true表示绕过Java的权限检测机制,false表示启用权限检测。上面调用了setAccessible(true)因此Java在访问的时候不会检测权限。这个方法在调用时需要虚拟机的ReflectPermission("suppressAccessChecks")权限。
为什么要访问private变量呢?因为有时候在串行化的时候必须要访问私有变量。
访问私有的方法也是类似。但是这种代码不宜使用太多,否则会造成程序混乱,无法维护。
下面是完整的代码:
import java.lang.reflect.*;
public class AccessPrivate {
public static void main(String[] argv) throws Exception {
// 定义一个测试对象
Foo foo = new Foo();
// 正常情况,测试函数
foo.show();
// 绕过Java权限检测
Class<Foo> fooClass = (Class<Foo>) foo.getClass();
Field messageField = fooClass.getDeclaredField("message");
messageField.setAccessible(true); // 绕过权限检测!
System.out.println("Foo is hacked!");
// 修改message变量
messageField.set(foo, "This is a Bar.");
// 再次调用测试函数
foo.show();
}
}
class Foo {
private String message = "This is a Foo.";
public void show() {
System.out.println(message);
}
}
另外,还有一种方法,就是通过编写native库进行访问,因为native中所有的访问都不需要权限检测。