【发布时间】:2012-01-19 17:47:42
【问题描述】:
在 Java 中,我通过这种方式加载外部类(在 .jar 文件中):
ClassLoader classLoader = new URLClassLoader(new URL[] {
new File("module.jar").toURI().toURL()});
Class clazz = classLoader.loadClass("my.class.name");
Object instance = clazz.newInstance();
//check and cast to an interface, then use it
if (instance instanceof MyInterface)
...
而且效果很好。
=====================
现在我想在 Scala 中做同样的事情。我有一个名为Module(Module.scala)的trait:
trait Module {
def name: String
}
object Module {
lazy val ModuleClassName = "my.module.ExModule"
}
我写了一个扩展Module的模块,然后编译成module.jar:
package my.module
import Module
object ExModule extends Module {}
然后我通过这段代码加载它:
var classLoader = new URLClassLoader(Array[URL](
new File("module.jar").toURI.toURL))
var clazz = classLoader.loadClass(Module.ModuleClassName)
它工作正常。但是如果我创建新实例,我会得到这个异常:
java.lang.InstantiationException: my.module.ExModule
如果我测试它:
clazz.isInstanceOf[Module]
-> 总是返回false。
那么你能帮我解决这个问题吗?
已编辑
我猜这是因为ExModule 是object(不是class)。但是当我将其更改为class 时,classLoader.loadClass(...) 会引发java.lang.NoClassDefFoundError。我猜这是因为ExModule 是从trait 扩展而来的。
我很困惑。谁能帮帮我?
已编辑
clazz.isInstanceOf[Class[Module]]//or Class[Byte], or Class[_]...
返回true。
【问题讨论】:
-
我认为你更接近于让它成为一个类(当你得到 ClassNotFoundException 时)。你确定当你引用 module.jar 时你得到了正确的路径吗?它从 trait 扩展而来的事实不应该有任何区别——ExModule 是一个类(在这种情况下)。
-
是的,我确定
module.jar的路径是正确的。方法classLoader.loadClass(...)工作正常(如果ExModule是object)。 -
你能看一下编译后的字节码(通过 javap 或类似的方式)吗? Scalac 有个有趣的习惯,就是到处添加 $s 和其他奇怪的名字,也许你的 ExModule 在编译后的版本中只是多了一个名字。此外,您可以要求 scalac 打印与您的 scala 相等的 java 代码(我现在不记得该选项了)。
-
@Rogach:好像是
my.module.ExModule$。当我用那个名字加载类时,我得到了java.lang.NoClassDefFoundError: scala/ScalaObject。然后我将/path/to/scala-library.jar添加到URLClassLoader(),得到java.lang.IllegalAccessException: Class main.scala.App$$anon$2$$anonfun$test$1 can not access a member of class my.module.ExModule$ with modifiers "private"