如何通过反射访问私有方法和私有数据成员?
Posted
技术标签:
【中文标题】如何通过反射访问私有方法和私有数据成员?【英文标题】:How do I access private methods and private data members via reflection? 【发布时间】:2012-07-14 01:56:48 【问题描述】:我知道我们可以通过反射访问私有构造函数,正如他在回答我的问题时提到的@Sanjay T. Sharma:Does “instanceof Void” always return false?
但是,@duffymosaid:
你可以通过反射访问私有的一切——方法、构造函数、数据成员,一切。
-
如何访问私有方法和私有数据成员?
是否可以通过反射访问局部变量?
有没有办法阻止任何人访问私有构造函数、方法和数据成员?
【问题讨论】:
局部变量存在于栈上,而不是堆上,所以这是一个完全不同的概念。但无论如何有趣的问题。 1.到处都是重复的,例如:***.com/questions/1555658/… @Thilo 那只是数据成员,方法呢?是不是一样的? ***.com/questions/880365/… (您可以查看SecurityManager
以使事情正常运行。(您可以通过调试/工具接口或字节码注入访问本地字段。)
【参考方案1】:
示例如下:
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));
【讨论】:
【参考方案2】:回答你的第三个问题:
-
有没有办法阻止任何人访问私有构造函数、方法和数据成员?
答案:
是的,您可以限制访问(当有人试图访问您的私有构造函数/方法/数据时,您可以抛出异常)
参考下面的例子:
******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
这个例子是一个单例类(检查构造函数),但你仍然可以为你想要阻止其他类访问的私有方法实现这个逻辑。
在这种情况下,您还将声明一个静态实例并在私有方法中检查它的值,并在出现任何不需要的值时抛出错误。
【讨论】:
【参考方案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) 是否可以通过反射访问局部变量?
没有。局部变量不能在创建它们的块之外访问(有人可能会说您可以将这样的变量分配给像 field = localVariable;
这样的字段,然后通过反射访问这样的字段,但是这样我们将访问 值,而不是变量)。
3) 有什么方法可以阻止任何人访问私有构造函数、方法和数据成员?
我认为对于constructors
或methods
,您可以使用stacktrace 来检查它是否被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
【讨论】:
【参考方案4】: 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]);
【讨论】:
【参考方案5】:要访问 私有字段,您需要调用
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
【讨论】:
【参考方案6】:-
使用您链接到的答案中显示的方法:setAccessible(true),它是 Field、Constructor 和 Method 的超类的方法。
没有。
不可以,除非代码在您控制的 JVM 中运行,您可以在其中安装安全管理器。但是,如果您给某人一个 jar 文件,他使用该 jar 文件中的类,他将能够访问所有内容。
【讨论】:
+1 所以这是Java的缺点之一?您无法保护您的以上是关于如何通过反射访问私有方法和私有数据成员?的主要内容,如果未能解决你的问题,请参考以下文章