如何使用反射在Java类外部调用私有方法而不会出现IllegalAccessException异常?

30
我有一个名为Dummy的类,其中有一个私有方法叫做sayHello。我想从Dummy外部调用sayHello。我认为可以使用反射来实现,但是我遇到了IllegalAccessException异常。有什么想法吗?

14
私有的概念不就是外部无法调用它吗? - PriestVallon
是的,使用反射是可能的,但私有的目的是使从外部调用方法更加困难。也许它不应该是私有的? - Louis Wasserman
@robert 它在同一个程序(模块)中。 - Hamed Rajabi Varamini
@HamedRajabi:你的意思是调用私有方法的类和你的Dummy类在同一个包中吗?如果是这种情况,你可能想使用package-private(省略修饰符)。 - Genzer
1
@PriestVallon 是的,我知道我不应该在真正的程序中这样做,我只是好奇!!! - Hamed Rajabi Varamini
5个回答

64
在使用`invoke`方法之前,需要在您的Method对象上调用`setAccessible(true)`。
import java.lang.reflect.*;
class Dummy{
    private void foo(){
        System.out.println("hello foo()");
    }
}

class Test{
    public static void main(String[] args) throws Exception {
        Dummy d = new Dummy();
        Method m = Dummy.class.getDeclaredMethod("foo");
        //m.invoke(d);// throws java.lang.IllegalAccessException
        m.setAccessible(true);// Abracadabra 
        m.invoke(d);// now its OK
    }
}

如果有人对使用参数调用方法感兴趣,请参考如何在给定方法名的情况下调用Java方法?,特别是像https://dev59.com/mnVC5IYBdhLWcg3w21Iq#30671481这样的答案。
只是在调用私有方法时不要忘记添加setAccessible(true)

4
因为getMethod仅返回公共方法,所以您需要使用getDeclaredMethod - Pshemo
1
如果该方法有参数,请参见Keyur的答案。 - user1521213
你应该用论据给出例子。 - vizzer
@vizzer 这个问题的主要问题/主题是IllegalAccessException,这意味着提问者和读者很可能已经了解使用反射调用方法的通用方式,但是他们在特别处理private方法时遇到了问题。我们已经有了很多关于通过反射调用带参数方法的问题和答案,例如https://dev59.com/mnVC5IYBdhLWcg3w21Iq#30671481,所以我不需要在这里重复,特别是因为该主题很宽泛,可能需要关于处理原始类型参数、getDeclaredMethod与getMethod之间的区别等问题的信息。 - Pshemo
1
无论如何,我在回答的底部链接了与该主题相关的问题。希望这样对你没问题。 - Pshemo

10

首先,你需要获取类,这很简单明了。然后使用getDeclaredMethod按名称获取方法,接下来需要在Method对象上使用setAccessible方法将该方法设置为可访问状态。

    Class<?> clazz = Class.forName("test.Dummy");

    Method m = clazz.getDeclaredMethod("sayHello");

    m.setAccessible(true);

    m.invoke(new Dummy());

你应该用论据给出例子。 - vizzer

9
method = object.getClass().getDeclaredMethod(methodName);
method.setAccessible(true);
method.invoke(object);

8
如果您想将任何参数传递给私有函数,可以将其作为invoke函数的第二个、第三个......参数传递。以下是示例代码。
Method meth = obj.getClass().getDeclaredMethod("getMyName", String.class);
meth.setAccessible(true);
String name = (String) meth.invoke(obj, "Green Goblin");

你可以在这里看到完整的示例。


7
使用Java反射访问私有方法(带参数)的示例如下:
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
class Test
{
    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");  //specify class name in quotes
        Object obj=c.newInstance();

        //----Accessing private Method
        Method m=c.getDeclaredMethod("call",new Class[]{int.class}); //getting method with parameters
        m.setAccessible(true);
        m.invoke(obj,7);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接