ClassNotFound(是的,我知道,有很多关于这个例外的帖子;我在这里和其他地方搜索过,找不到解释)
为什么Class.forName会失败?
groovy> class Foo {
groovy> }
groovy> def f = new Foo()
groovy> def cname = f.getClass().getName()
groovy> def p = f.getClass().getPackage()
groovy> def l = f.getClass().getClassLoader()
groovy> println "Foo class name: $cname"
groovy> println "Foo package: $p"
groovy> println "Foo class loader: ${f.getClass().getClassLoader().toString()}"
groovy> println "Current class loader: ${this.getClass().getClassLoader().toString()}"
groovy> try {
groovy> Class.forName(cname)
groovy> } catch (Exception e) {
groovy> println e
groovy> }
groovy> l.findClass("Foo")
Foo class name: Foo
Foo package: null
Foo class loader: groovy.lang.GroovyClassLoader$InnerLoader@2d275595
Current class loader: groovy.lang.GroovyClassLoader$InnerLoader@2d275595
java.lang.ClassNotFoundException: Foo
Exception thrown
Oct 16, 2012 4:43:28 PM org.codehaus.groovy.runtime.StackTraceUtils sanitize
WARNING: Sanitizing stacktrace:
java.lang.ClassNotFoundException: Foo
谢谢!
答案 0 :(得分:3)
给出的答案基本上是正确的,但缺少一个重要的信息位。 Class.forName(String)
是从Java调用Java的Java方法。它需要让类加载器加载给定的类。它通过使用内部方法来获取加载程序来调用堆栈。虽然java上升一级是正常的,但在Groovy中并不正确。 Groovy中的每个方法调用都可以包含来自生成方法的可变数量的中间调用堆栈元素,来自invokedynamic和来自反射。但通常父调用堆栈帧不包含真正的调用者类。相反,您最终会在groovy运行时的加载器中结束,甚至在Java运行时的加载器中结束。你的shell中的类是那些的子类,因此加载器不可能找到所请求的类。
答案 1 :(得分:2)
这是由ClassLoader引起的。 shell中的ClassLoader(即您在shell中定义的类)与运行shell的ClassLoader(运行shell所需的jar)不同。这就是为什么命令Class.forName("Foo", true, this.class.classLoader)
有效,因为你在shell中指定了ClassLoader
试
def shell=new GroovyShell()
def f=shell.evaluate("class Foo{Foo(){println this.class.classLoader}};def f=new Foo()")
println shell.class.classLoader
shell.evaluate("println this.class.classLoader")
println "-----------"
println Class.forName("Foo", true, f.class.classLoader)
println Class.forName("Foo", true, this.class.classLoader)
您将看到第一个Class.forName有效,而不是第二个。运行脚本是类似的,因为它将创建一个不共享shell的ClassLoader
的脚本类在脚本的上下文中,执行Class.forName将不会使用与此相同的内容。
不确定它是否足够清晰:(