1

我正在测试从另一个类访问私有方法的示例并遇到异常

public class WithoutMain 
{       
    public static void main(String args[]) throws Exception
    {
        Class c = Class.forName("A");
        Object o = c.newInstance();
        Method m = c.getDeclaredMethod("message", null);
        m.setAccessible(true);
        m.invoke(o, null);
    }
}

public class A {

    private void message(){ 
        System.out.println("This is a private method.");
    }
}

得到以下异常

Exception in thread "main" java.lang.ClassNotFoundException: A
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)

这 2 个类位于同一个包中。谁能告诉我为什么会出现这个异常?

4

6 回答 6

4

您需要使用类的完全限定名称来加载它Class.forName()

现在你可能会争论为什么?与您的情况一样,这两个类都在同一个目录/包中。

我会争辩另一种方式,java中没有定义类加载器首先在同一目录中查找的规则。

如果您想了解类加载的工作原理,我建议您使用类的源java.lang.ClassLoader代码

因此,当您调用它时,Class.forName它使用委托,并且分配了加载此类作业的类加载器将不知道当前包或任何位置。因此,它需要完全限定的类名。

还有一个提示,在 java 中,已加载类的完全限定类名是<ClassLoader><packageName><className>. 这就是 JVM 中的类是如何唯一标识的。

希望这可以帮助

编辑

您的代码只能在一种情况下工作,也就是说,如果两个类都在默认包中。

于 2013-08-31T18:55:34.897 回答
2

您必须提供类的完全限定名,而不仅仅是简单的类名。

Class c = Class.forName("<package>.A");
于 2013-08-31T18:54:45.073 回答
1

尝试改变

    Class c = Class.forName("A");

    Class c = Class.forName("yourPackagePath.A");

forName 方法不考虑用户调用的包。

于 2013-08-31T18:54:32.640 回答
1

根据文档,您需要 FQN :

参数:
   className - 所需类的完全限定名。

于 2013-08-31T18:55:27.237 回答
0

Java Class 类不在您的包中,因此它需要知道该类的位置,否则它不知道要加载它的位置(就像类加载器从完整文件路径加载它一样)。

所以

Class<? extends Object> c = Class.forName("A");

需要是

Class<? extends Object> c = Class.forName("package.A");

其中 package 是包的完整限定名,所以如果包是

foo.bar

它会变成

Class<? extends Object> c = Class.forName("foo.bar.A");
于 2013-08-31T19:03:56.827 回答
0

如前所述,需要全名。

为避免手动输入,您可以简单地使用:

Class<?> clazz = Class.forName(A.class.getName());
于 2013-08-31T19:10:19.943 回答