问题描述
ClassLoader classLoader = new URLClassLoader(在Java文件中) new URL [] {
new File(module.jar)。toURI()。toURL()});
Class clazz = classLoader.loadClass(my.class.name);
对象实例= clazz.newInstance();
//检查并转换到一个接口,然后使用它
if(instance instanceof MyInterface)
...
它的工作正常。
============ ======
现在我想在Scala中做同样的事情。我有一个 trait
命名为 Module
( Module.scala
) :
trait模块{
def name:String
}
对象模块{
lazy val ModuleClassName =my.module.ExModule
}
我写一个扩展 Module
的模块,然后将其编译为 module.jar
:
package my.module
import模块
对象ExModule extends Module {}
然后我用这段代码加载:
code> var classLoader = new URLClassLoader(Array [URL](
new File(module.jar)。toURI.toURL))
var clazz = classLoader.loadClass(Module.ModuleClassName)
它工作正常。但是如果我创建新的实例,我得到这个例外:
java.lang.InstantiationException:my.module.ExModule
如果我测试:
code> clazz.isInstanceOf [Module]
- >总是返回
。
你能帮我解决这个问题吗?
编辑
我猜是因为 ExModule
是一个 / code>(不是
class
)。但是当我将它更改为 class
,而 classLoader.loadClass(...)
提出了一个 java.lang.NoClassDefFoundError
。我想这是因为 ExModule
从 trait
中扩展。
我很困惑任何人都可以帮助我吗?
已编辑
clazz.isInstanceOf [Class [Module]] //或Class [Byte]或Class [_] ...
返回 true
。
糟糕。我得到了答案。
了解:
-
(再次感谢Neil)。
-
========= ============================================================================================================================================================================================ / trait ...从外部jar文件。还是因为我找不到正确的方法。但是目前这有助于我解决问题。
var classLoader = new java.net.URLClassLoader(
Array新的File(module.jar)toURI.toURL),
/ *
*需要指定parent,所以我们在当前上下文中有所有的类实例
*
* /
this.getClass.getClassLoader
/ *
*请注意,后缀$用于Scala对象,
*这是一个技巧b $ b * /
var clazzExModule = classLoader.loadClass(Module.ModuleClassName +$)
/ *
*目前,我不知道如何检查clazzExModule是
* Class [Module]的实例,因为clazzExModule.isInstanceOf [Class [_]]总是
*返回true,
*所以我使用try / catch
* /
尝试{
//MODULE $是一个技巧,我不知道get(null)
var module = clazzExModule.getField(MODULE $)。 get(null).asInstanceOf [Module]
} catch {
case e:java.lang.ClassCastException =>
printf( - %s不是Module\\\
,clazzExModule)
}
这就是: - )
已编辑
更好的设计 ExModule
作为一个类。从jar文件加载后,我可以像下面这样查看:
var clazz = classLoader.loadClass(Module.ModuleClassName)
if(classOf [Module] .isAssignableFrom(clazz))
...
注意:
你不能这样做:
if(clazz.isAssignableFrom(classOf [Module]))
因为模块
是一个 trait
/ 对象
, isAssignableFrom()
在这种情况下不起作用。
In Java, I load external class (in .jar file) by this way:
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 trait
named 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
:
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
.
So could you help me on this problem?
Edited
I guess it is because ExModule
is an object
(not class
). But when I change it to class
, and classLoader.loadClass(...)
raises a java.lang.NoClassDefFoundError
. I guess it is because ExModule
is extended from a trait
.
I'm confused. Could anyone please help me?
Edited
clazz.isInstanceOf[Class[Module]]//or Class[Byte], or Class[_]...
returns true
.
Oops... I got the answer.
Learn from:
https://stackoverflow.com/a/8868537/942821 (thanks Neil again).
====================
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.
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 ExModule
as a class. After loading it from jar file, I can check it as like as:
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 Module
is a trait
/object
, isAssignableFrom()
will not work in this case.
这篇关于Scala - 动态对象/类加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!