我的代码大致如下:
val classLoader = new URLClassLoader(entry.jars, Thread.currentThread.getContextClassLoader)
val env = classLoader.loadClass(entry.name).asSubclass(classOf[Environment])
对于上下文:"条目"是JAR文件和类名的集合。该课程预计将延长Environment
。 Environment
在同一个包中定义,并且不使用任何类加载技巧。 JAR文件的集合仅包含指定类所需的类,仅此而已(仅限任何父级ClassLoader
已加载的内容)。
当我使用run
从sbt中运行这段代码时,一切正常。但是如果我在同一个sbt shell中第二次运行它,我会得到:
[error] (run-main-1) java.lang.ClassCastException: class edu.tum.cs.isabelle.impl.Environment
java.lang.ClassCastException: class edu.tum.cs.isabelle.impl.Environment
at java.lang.Class.asSubclass(Class.java:3404)
我无法理解这里的问题:在运行之间没有重新编译或任何东西。我为test
执行了类似的代码,它在那里工作正常。当我将fork
设置为true
时,它确实有效,但我没有理由这样做。
为了进行调试,我检查了getClassLoader
classOf[Environment]
以及加载类的超类。果然,在第一次运行中,它们是等效的,但不是在第二次运行中。不过,他们的toString
表示是不确定的。
编辑:更多调试。我打印出所有相关类加载器的System.identityHashCode
:
println(s"self: " + System.identityHashCode(classOf[Environment].getClassLoader))
println(s"fresh: " + System.identityHashCode(classLoader))
println(s"impl: " + System.identityHashCode(classLoader.loadClass(entry.name).getClassLoader))
println(s"impl.parent: " + identityHashCode(classLoader.loadClass(entry.name).getSuperclass.getClassLoader))
首次运行的结果:
self: 1209891953
fresh: 1734438968
impl: 1734438968
impl.parent: 1209891953
第二轮的结果:
self: 1952422714
fresh: 1110295313
impl: 1110295313
impl.parent: 1209891953
答案 0 :(得分:1)
Rob Norris在其他地方提出了解决方案。由于当前Thread的类加载器可以是"字面上任何",我应该确保使用用于加载Environment
的类加载器。果然,如果我将代码更改为
val classLoader = new URLClassLoader(entry.jars, getClass.getClassLoader)
代码按预期工作。