在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)
...
Run Code Online (Sandbox Code Playgroud)
它工作正常.
====================
现在我想在Scala中做同样的事情.我有一个trait名字Module(Module.scala):
trait Module {
def name: String
}
object Module {
lazy val ModuleClassName = "my.module.ExModule"
}
Run Code Online (Sandbox Code Playgroud)
我编写了一个扩展模块Module,然后将其编译为module.jar:
package my.module
import Module
object ExModule extends Module {}
Run Code Online (Sandbox Code Playgroud)
然后我用这段代码加载它:
var classLoader = new URLClassLoader(Array[URL](
new File("module.jar").toURI.toURL))
var clazz = classLoader.loadClass(Module.ModuleClassName)
Run Code Online (Sandbox Code Playgroud)
它工作正常.但是如果我创建新实例,我会得到以下异常:
java.lang.InstantiationException: my.module.ExModule
Run Code Online (Sandbox Code Playgroud)
如果我测试它:
clazz.isInstanceOf[Module]
Run Code Online (Sandbox Code Playgroud)
- >总是回来false.
你能帮我解决这个问题吗?
编辑
我想这是因为ExModule是object(不class).但是,当我改变它class,并classLoader.loadClass(...)提出一个java.lang.NoClassDefFoundError.我想这是因为ExModule从a扩展trait.
我糊涂了.有人可以帮帮我吗?
编辑
clazz.isInstanceOf[Class[Module]]//or Class[Byte], or Class[_]...
Run Code Online (Sandbox Code Playgroud)
回报true.
小智 12
哎呀......我得到了答案.
借鉴:
/sf/answers/620797621/(再次感谢Neil).
====================
我想在Scala团队提供object/class/trait从外部jar文件加载...的正确方法之前,这种方式是暂时的.或者因为我找不到正确的方法.但目前这有助于我摆脱困境.
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)
}
Run Code Online (Sandbox Code Playgroud)
就这样 :-)
编辑
我最好设计ExModule成一个班级.从jar文件加载后,我可以检查它:
var clazz = classLoader.loadClass(Module.ModuleClassName)
if (classOf[Module].isAssignableFrom(clazz))
...
Run Code Online (Sandbox Code Playgroud)
注意:
你不能以相反的方式做到这一点:
if (clazz.isAssignableFrom(classOf[Module]))
Run Code Online (Sandbox Code Playgroud)
因为Module是trait/ object,isAssignableFrom()在这种情况下不起作用.