Scala脚本:在Windows上向ScalaClassLoader解释此类强制转换错误
请考虑以下
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? 编辑: 在跑步时:
输出是: [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] 所以肯定会有一些阴暗的类加载.现在试着调查为什么会这样 解决方法
如果您将代码扩展一点,如下所示:
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) } } 你会得到以下输出:
注意匹配哈希@ 5cee5251. 您可以在ScalaClassLoader.asContext方法中找到一些详细信息,您可以在堆栈跟踪中看到,它使用Thread.setContextClassLoader将自身设置为执行脚本的线程的主类加载器. 更新(为什么它在Mac上运行但在Windows上不起作用) * nix的scala shell脚本和Windows的scala.bat之间的主要区别在于默认情况下* nix平台标准Scala库被添加到Boot Classpath(请参阅脚本中的usebootcp),而在Windows上它们被添加到“常用类路径” ”.这很重要,因为它定义了哪个类加载器将加载scala.tools.nsc.MainGenericRunner使用的scala.reflect.internal.util.ScalaClassLoader:它是否为根类加载器(如果调用getClassLoader则表示为null)或Application Class Loader(即sun.misc.Launcher $AppClassLoader的实例).这很重要,因为 def run(urls: Seq[URL],objectName: String,arguments: Seq[String]) { (ScalaClassLoader fromURLs urls).run(objectName,arguments) } 这意味着“主”ScalaClassLoader的父类加载器将是引导类加载器而不是sun.misc.Launcher $AppClassLoader,因此当你向scala.reflect.internal.util.ScalaClassLoader类询问这个“主”ScalaClassLoader时它可以在类加载器链加载的类中找不到它,因此必须再次加载它.这就是为什么脚本中有两个不同的ScalaClassLoader类实例的原因. 有两个明显的解决方法(两者都不太好): >更改Scala源中的CommonRunner.run,实际将当前上下文类加载器作为新ScalaClassLoader的父级传递(可能不那么容易?) # 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. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |