Scala - 动态对象/类加载

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8867766/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 03:48:47  来源:igfitidea点击:

Scala - Dynamic object/class loading

scalaobjectdynamicload

提问by

In Java, I load external class (in .jar file) by this way:

在 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)
  ...

And it works fine.

它工作正常。

====================

====================

Now I want to do the same thing in Scala. I have a traitnamed Module(Module.scala):

现在我想在 Scala 中做同样的事情。我有一个trait名为Module( Module.scala):

trait Module {
  def name: String
}

object Module {
  lazy val ModuleClassName = "my.module.ExModule"
}

I write a module extending Module, then compile it to module.jar:

我编写了一个扩展模块Module,然后将其编译为module.jar

package my.module

import Module

object ExModule extends Module {}

Then I load it by this code:

然后我通过这个代码加载它:

var classLoader = new URLClassLoader(Array[URL](
  new File("module.jar").toURI.toURL))
var clazz = classLoader.loadClass(Module.ModuleClassName)

It works fine. But if I create new instance, I get this exception:

它工作正常。但是,如果我创建新实例,则会出现此异常:

java.lang.InstantiationException: my.module.ExModule

If I test it:

如果我测试它:

clazz.isInstanceOf[Module]

-> always return false.

-> 总是返回false

So could you help me on this problem?

那么你能帮我解决这个问题吗?

Edited

已编辑

I guess it is because ExModuleis an object(not class). But when I change it to class, and classLoader.loadClass(...)raises a java.lang.NoClassDefFoundError. I guess it is because ExModuleis extended from a trait.

我想这是因为ExModuleobject(不是class)。但是当我将其更改为class, 并classLoader.loadClass(...)引发java.lang.NoClassDefFoundError. 我想这是因为它是ExModuletrait.

I'm confused. Could anyone please help me?

我糊涂了。有人可以帮我吗?

Edited

已编辑

clazz.isInstanceOf[Class[Module]]//or Class[Byte], or Class[_]...

returns true.

返回true

采纳答案by

Oops... I got the answer.

哎呀...我得到了答案。

Learn from:

借鉴:

====================

====================

I guess this way is temporary before Scala team provides right way to load an object/class/trait... from external jar file. Or because I can't find out the right way. But currently this helps me out of the problem.

我想这种方式在 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)
}

That's all :-)

就这样 :-)

Edited

已编辑

I'd better design ExModuleas a class. After loading it from jar file, I can check it as like as:

我最好把设计ExModule当成一个班级。从 jar 文件加载后,我可以像这样检查它:

var clazz = classLoader.loadClass(Module.ModuleClassName)
if (classOf[Module].isAssignableFrom(clazz))
  ...

Note:

笔记:

You can not do it the opposite way:

你不能以相反的方式做到这一点:

if (clazz.isAssignableFrom(classOf[Module]))

because Moduleis a trait/object, isAssignableFrom()will not work in this case.

因为Moduletrait/ objectisAssignableFrom()在这种情况下不起作用。