如何通过reflection访问私有方法和私有数据成员?

我知道我们可以通过reflection访问私人构造函数@Sanjay T. Sharma在他的回答中提到我的问题: “instanceof Void”是否总是返回false?

不过, @duffymo 说 :

你可以用reflection访问私有的东西 – 方法,构造函数,数据成员,一切。

  1. 我如何访问私有方法和私有数据成员?
  2. 是否有可能通过reflection访问本地variables?
  3. 有没有办法阻止任何人访问私人构造函数,方法和数据成员?

1) 如何访问私有方法和私有数据成员?

你可以用setAccessible(true)方法的一点帮助来做到这一点:

 class Dummy{ private void foo(){ System.out.println("hello foo()"); } private int i = 10; } class Test{ public static void main(String[] args) throws Exception { Dummy d = new Dummy(); /*--- [INVOKING PRIVATE METHOD] ---*/ Method m = Dummy.class.getDeclaredMethod("foo"); //m.invoke(d); // Exception java.lang.IllegalAccessException m.setAccessible(true);//Abracadabra m.invoke(d); // Now it's OK /*--- [GETING VALUE FROM PRIVATE FIELD] ---*/ Field f = Dummy.class.getDeclaredField("i"); //System.out.println(f.get(d)); // Not accessible now f.setAccessible(true); // Abracadabra System.out.println(f.get(d)); // Now it's OK /*--- [SETTING VALUE OF PRIVATE FIELD] ---*/ Field f2 = Dummy.class.getDeclaredField("i"); //f2.set(d,20); // Not accessible now f2.setAccessible(true); // Abracadabra f2.set(d, 20); // Now it's OK System.out.println(f2.get(d)); } } 

2) 是否有可能通过reflection访问本地variables?

不能。局部variables不能在创build它们的块之外被访问(有人可以说你可以把这样一个variables赋给一个像field = localVariable;后来通过reflection访问这个域,但是这样我们将会访问 ,而不是variables )。

3) 有没有办法阻止任何人访问私有构造函数,方法和数据成员?

我认为对于constructors或者methods你可以使用stacktrace来检查它是否被Reflection调用。
对于字段,我找不到解决scheme,以防止通过reflection访问它们。

[警告:这是不被任何人批准的。 我刚刚写了这个启发你的问题。]

 class Dummy { private void safeMethod() { StackTraceElement[] st = new Exception().getStackTrace(); // If a method was invoked by reflection, the stack trace would be similar // to something like this: /* java.lang.Exception at package1.b.Dummy.safeMethod(SomeClass.java:38) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) -> at java.lang.reflect.Method.invoke(Method.java:601) at package1.b.Test.main(SomeClass.java:65) */ //5th line marked by "->" is interesting one so I will try to use that info if (st.length > 5 && st[4].getClassName().equals("java.lang.reflect.Method")) throw new RuntimeException("safeMethod() is accessible only by Dummy object"); // Now normal code of method System.out.println("code of safe method"); } // I will check if it is possible to normally use that method inside this class public void trySafeMethod(){ safeMethod(); } Dummy() { safeMethod(); } } class Dummy1 extends Dummy {} class Test { public static void main(String[] args) throws Exception { Dummy1 d1 = new Dummy1(); // safeMethod can be invoked inside a superclass constructor d1.trySafeMethod(); // safeMethod can be invoked inside other Dummy class methods System.out.println("-------------------"); // Let's check if it is possible to invoke it via reflection Method m2 = Dummy.class.getDeclaredMethod("safeMethod"); // m.invoke(d);//exception java.lang.IllegalAccessException m2.setAccessible(true); m2.invoke(d1); } } 

Test主要方法的输出

 code of safe method code of safe method ------------------- Exception in thread "main" java.lang.reflect.InvocationTargetException at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:601) at package1.b.Test.main(MyClass2.java:87) Caused by: java.lang.RuntimeException: method safeMethod() is accessible only by Dummy object at package1.b.Dummy.safeMethod(MyClass2.java:54) ... 5 more 
  1. 使用您在答案中显示的方法链接到: setAccessible(true) ,这是Field,Constructor和Method的超类方法。
  2. 没有。
  3. 否,除非代码在您控制的JVM中运行,您需要在其中安装安全pipe理器。 但是如果你给某人一个jar文件,并且使用这个jar文件中的类,他将能够访问所有的东西。

要访问 私有字段,您需要调用Class.getDeclaredField(String name)enter code here方法。 检查这个简单的代码:

 public class PrivateObject { private String privateString = null; public PrivateObject(String privateString) { this.privateString = privateString; } } PrivateObject privateObject = new PrivateObject("The Private Value"); Field privateStringField = PrivateObject.class. getDeclaredField("privateString"); privateStringField.setAccessible(true); String fieldValue = (String) privateStringField.get(privateObject); System.out.println("fieldValue = " + fieldValue 

要访问私有方法,您将需要调用Class.getDeclaredMethod(String name,Class [] parameterTypes)或Class.getDeclaredMethods()方法。

检查这个简单的代码:

 public class PrivateObject { private String privateString = null; public PrivateObject(String privateString) { this.privateString = privateString; } private String getPrivateString(){ return this.privateString; } } PrivateObject privateObject = new PrivateObject("The Private Value"); Method privateStringMethod = PrivateObject.class. getDeclaredMethod("getPrivateString", null); privateStringMethod.setAccessible(true); String returnValue = (String) privateStringMethod.invoke(privateObject, null); System.out.println("returnValue = " + returnValue); 

http://tutorials.jenkov.com/java-reflection/private-fields-and-methods.html阅读详细信息;

  Area s=(Area)c.newInstance(); s.setRadius(10); System.out.println("Area: "+s.calculateArea(4)); Method m[]=c.getDeclaredMethods(); Constructor c1[]=c.getConstructors(); for(int i=0;i<m.length;i++) System.out.println(""+m[i]); for(int i=0;i<c1.length;i++) System.out.println(""+c1[i]); 

示例如下:

 import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; class Test { private int a = 5; // Private data member private void call(int n) // Private method { System.out.println("in call() n: " + n); } } public class Sample { public static void main(String args[]) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException { Class c = Class.forName("Test"); Object obj = c.newInstance(); //---- Accessing a private method Method m=c.getDeclaredMethod("call",new Class[]{int.class}); m.setAccessible(true); m.invoke(obj,7); //---- Accessing a private data member Field d = c.getDeclaredField("a"); d.setAccessible(true); System.out.println(d.getInt(obj)); } } 

要回答你的第三个问题:

  1. 有没有办法阻止任何人访问私人构造函数,方法和数据成员?

回答:

是的,你可以限制访问(当有人试图访问你的私有构造函数/方法/数据时,你可以抛出exception)

参考下面的例子:

 ******JavaSingleton Class****** package server; public class JavaSingleton { private static final JavaSingleton INSTANCE = new JavaSingleton(); private JavaSingleton() { if (INSTANCE != null) { throw new IllegalStateException("Inside JavaSingleton(): JavaSingleton " + "instance already created."); } System.out.println("Inside JavaSingleton(): Singleton instance is being created."); } public static final JavaSingleton getInstance() { return INSTANCE; } } ***Listing 2: JavaSingleton client*** import server.JavaSingleton; import java.lang.reflect.*; public class TestSingleton { public static void main(String[] args) throws ReflectiveOperationException { System.out.println("Inside main(): Getting the singleton instance using getInstance()..."); JavaSingleton s = JavaSingleton.getInstance(); System.out.println("Inside main(): Trying to use reflection to get another instance..."); Class<JavaSingleton> clazz = JavaSingleton.class; Constructor<JavaSingleton> cons = clazz.getDeclaredConstructor(); cons.setAccessible(true); JavaSingleton s2 = cons.newInstance(); } } Output: C:\singleton>java TestSingleton Inside main(): Getting the singleton instance using getInstance()... Inside JavaSingleton(): Singleton instance is being created. Inside main(): Trying to use reflection to get another instance... Exception in thread "main" java.lang.reflect.InvocationTargetException at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source) at java.lang.reflect.Constructor.newInstance(Unknown Source) at TestSingleton.main(TestSingleton.java:13) Caused by: java.lang.IllegalStateException: Inside JavaSingleton(): JavaSingleton instance already created. at server.JavaSingleton.<init>(JavaSingleton.java:7) ... 5 more 

这个例子是用于单例类(检查构造函数),但是你仍然可以为你想阻止其他类访问的私有方法实现这个逻辑。

在这种情况下,您还将声明一个静态实例并在私有方法中检查它的值,并在出现任何不需要的值时抛出错误。