在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中做同样的事情。我有trait
名为Module
(Module.scala
):
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
。
答案 0 :(得分:9)
哎呀......我得到了答案。
学习:
https://stackoverflow.com/a/8868537/942821(再次感谢Neil。)
====================
我猜这种方式是临时的,因为Scala团队提供了从外部jar文件加载object/class/trait
...的正确方法。或者因为我找不到正确的方法。但目前这有助于我解决问题。
var classLoader = new java.net.URLClassLoader(
Array(new File("module.jar").toURI.toURL),
/*
* need to specify parent, so we have all class instances
* in current context
*/
this.getClass.getClassLoader)
/*
* please note that the suffix "$" is for Scala "object",
* it's a trick
*/
var clazzExModule = classLoader.loadClass(Module.ModuleClassName + "$")
/*
* currently, I don't know how to check if clazzExModule is instance of
* Class[Module], because clazzExModule.isInstanceOf[Class[_]] always
* returns true,
* so I use try/catch
*/
try {
//"MODULE$" is a trick, and I'm not sure about "get(null)"
var module = clazzExModule.getField("MODULE$").get(null).asInstanceOf[Module]
} catch {
case e: java.lang.ClassCastException =>
printf(" - %s is not Module\n", clazzExModule)
}
这就是全部: - )
<强>被修改强>
我最好将ExModule
设计成一个班级。从jar文件加载后,我可以像下面这样检查:
var clazz = classLoader.loadClass(Module.ModuleClassName)
if (classOf[Module].isAssignableFrom(clazz))
...
注意:强> 的
你不能以相反的方式做到这一点:
if (clazz.isAssignableFrom(classOf[Module]))
因为Module
是trait
/ object
,isAssignableFrom()
在这种情况下不起作用。
答案 1 :(得分:0)