请考虑使用以下scala脚本:
import scala.reflect.internal.util.ScalaClassLoader
object Test {
def main(args: Array[String]) {
val classloaderForScalaLibrary = classOf[ScalaClassLoader.URLClassLoader].getClassLoader
println(classloaderForScalaLibrary)
val classloaderForTestClass = this.getClass.getClassLoader
println(classloaderForTestClass)
this.getClass.getClassLoader.asInstanceOf[ScalaClassLoader.URLClassLoader]
}
}
输出结果为:
scala.reflect.internal.util.ScalaClassLoader$URLClassLoader@71c8becc
scala.reflect.internal.util.ScalaClassLoader$URLClassLoader@71c8becc
java.lang.ClassCastException: scala.reflect.internal.util.ScalaClassLoader$URLClassLoader cannot be cast to scala.reflect.internal.util.ScalaClassLoader$URLClassLoader
at Main$.main(Test.scala:8)
at Main.main(Test.scala)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at scala.reflect.internal.util.ScalaClassLoader.$anonfun$run$2(ScalaClassLoader.scala:98)
at scala.reflect.internal.util.ScalaClassLoader.asContext(ScalaClassLoader.scala:32)
...
为什么我无法将ScalaClassLoader$URLClassLoader
投射到ScalaClassLoader$URLClassLoader
?
修改
跑步时:
scala -J-verbose:class Test.scala | grep ScalaClassLoader
输出结果为:
[Loaded scala.reflect.internal.util.ScalaClassLoader$URLClassLoader from file:/C:/Development/Software/scala-2.12.2/lib/scala-reflect.jar]
...
...
[Loaded scala.reflect.internal.util.ScalaClassLoader$URLClassLoader from file:/C:/DEVELO~1/Software/SCALA-~1.2/lib/scala-reflect.jar]
所以肯定会有一些阴暗的类加载。现在试图调查为什么会这样
答案 0 :(得分:2)
如果您将代码扩展得更多,如下所示:
import scala.reflect.internal.util.ScalaClassLoader
object test {
def main(args: Array[String]) {
val cl1 = this.getClass.getClassLoader
println(cl1)
val c1 = cl1.getClass
println(cl1.getClass)
println(cl1.getClass.getClassLoader)
println("-------")
var c2 = classOf[ScalaClassLoader.URLClassLoader]
println(c2)
println(c2.getClassLoader)
println("-------")
println(c1 == c2)
}
}
你会得到以下输出:
scala.reflect.internal.util.ScalaClassLoader$URLClassLoader@5cee5251
类scala.reflect.internal.util.ScalaClassLoader $ URLClassLoader
sun.misc.Launcher$AppClassLoader@4554617c
-------
类scala.reflect.internal.util.ScalaClassLoader $ URLClassLoader
scala.reflect.internal.util.ScalaClassLoader$URLClassLoader@5cee5251
-------
假
注意匹配哈希@5cee5251
。
这意味着第一个Scala解释器使用根Java类加载器加载ScalaClassLoader$URLClassLoader
,然后使用该类加载器加载脚本中的所有类,当您在代码中请求ScalaClassLoader$URLClassLoader
时,它将加载另一个(已加载)ScalaClassLoader$URLClassLoader
的实例。通过这种方式,您的脚本将与执行它的“运行时环境”隔离开来。
您可以在ScalaClassLoader.asContext方法中找到一些详细信息,您可以在堆栈跟踪中看到,使用Thread.setContextClassLoader将自己设置为执行脚本的线程的主类加载器。
更新(为什么它在Mac上运行但在Windows上不起作用)
* nix的scala
shell脚本和Windows的scala.bat
之间的主要区别在于,默认情况下* nix平台上的标准Scala库被添加到Boot Classpath(请参阅usebootcp
在Windows上,它们被添加到“常用类路径”中。这很重要,因为它定义了哪个类加载器将加载scala.reflect.internal.util.ScalaClassLoader
使用的scala.tools.nsc.MainGenericRunner
:它是否为根类加载器(如果调用null
,则表示为getClassLoader
})或Application Class Loader(即sun.misc.Launcher$AppClassLoader
的实例)。这很重要,因为CommonRunner.run
只使用ScalaClassLoader
而不使用urls
parent
的实例
def run(urls: Seq[URL], objectName: String, arguments: Seq[String]) {
(ScalaClassLoader fromURLs urls).run(objectName, arguments)
}
这意味着“main”ScalaClassLoader
的父类加载器将是引导类加载器而不是sun.misc.Launcher$AppClassLoader
,因此当您向类{{ScalaClassLoader
询问此类scala.reflect.internal.util.ScalaClassLoader
时1}}它无法在类加载器链加载的类中找到它,因此必须再次加载它。这就是您在脚本中有两个不同的ScalaClassLoader
类 实例的原因。
有两个明显的解决方法(两者都不太好):
CommonRunner.run
更改为实际将当前上下文类加载器作为新ScalaClassLoader
的父级传递(可能不那么容易<)scala.bat
更改为使用-Xbootclasspath/a:
而不是-cp
%_TOOL_CLASSPATH%
。但是,查看* nix脚本中的usebootcp
,我可以看到以下注释:# default to the boot classpath for speed, except on cygwin/mingw/msys because
# JLine on Windows requires a custom DLL to be loaded.
unset usebootcp
if [[ -z "$cygwin$mingw$msys" ]]; then
usebootcp="true"
fi
所以我怀疑如果你想将scala.bat
用于REPL,将所有Scala库移动到Boot Classpath可能是一个坏主意。如果是这种情况,您可能需要创建scala.bat
的副本(例如scala_run_script.bat
)进行更改并使用它来运行Scala脚本,为REPL留下标准scala.bat
。