scala 类加载器困惑

标签 scala classloader

请考虑以下测试程序(使用scala 2.9.0.1)

object test
{
  def main(args:Array[String]) = {
    println(ClassLoader.getSystemClassLoader.getResource("toto"))
    println(this.getClass.getClassLoader.getResource("toto"))
    println(classOf[Object].getClassLoader)
  }
}

我编译它并使用包含文件“toto”的“-cp/tmp”运行它,并得到以下输出:

null
file:/tmp/toto
null

=> 系统类加载器不包含类路径

=> Object 类没有类加载器!

我是否遗漏了一些东西,或者它是 scala 中的一个(大)错误?!

谢谢, 阿琼

最佳答案

第二个 null 的解释为 java.lang.Class#getClassLoader()

Returns the class loader for the class. Some implementations may use null to represent the bootstrap class loader. This method will return null in such implementations if this class was loaded by the bootstrap class loader.

所以,这就是为什么 classOf[Object].getClassLoader 返回 null,它是由引导类加载器加载的(它在 rt.jar 中,更具体地说,它在 $ 中的 jar 中) JAVA_HOME/lib)。

第一个 null 更难解释。看来 Scala 按原样保留系统类加载器,只将选项 -cp 添加到它自己的类加载器(scala/util/ClassLoader.scala 中的 ScalaClassLoader)。

使用以下内容:

object Test {
  def main(args:Array[String]) = {
    println(ClassLoader.getSystemClassLoader)
    println(this.getClass.getClassLoader)
    println(classOf[Object].getClassLoader)
  }
}

并运行它:

$ scala -cp /temp Test

我们得到以下输出:

sun.misc.Launcher$AppClassLoader@11b86e7
URLClassLoader(
  file:/C:/developpement/utils/jdk1.6.0_22/jre/lib/resources.jar
  file:/C:/developpement/utils/jdk1.6.0_22/jre/lib/rt.jar
  file:/C:/developpement/utils/jdk1.6.0_22/jre/lib/jsse.jar
  file:/C:/developpement/utils/jdk1.6.0_22/jre/lib/jce.jar
  file:/C:/developpement/utils/jdk1.6.0_22/jre/lib/charsets.jar
  file:/C:/developpement/utils/jdk1.6.0_22/jre/lib/ext/dnsns.jar
  file:/C:/developpement/utils/jdk1.6.0_22/jre/lib/ext/localedata.jar
  file:/C:/developpement/utils/jdk1.6.0_22/jre/lib/ext/sunjce_provider.jar
  file:/C:/developpement/utils/jdk1.6.0_22/jre/lib/ext/sunmscapi.jar
  file:/C:/developpement/utils/jdk1.6.0_22/jre/lib/ext/sunpkcs11.jar
  file:/C:/DEVELO~1/scala/SCALA-~1.1/bin/../lib/jline.jar
  file:/C:/DEVELO~1/scala/SCALA-~1.1/bin/../lib/scala-compiler.jar
  file:/C:/DEVELO~1/scala/SCALA-~1.1/bin/../lib/scala-dbc.jar
  file:/C:/DEVELO~1/scala/SCALA-~1.1/bin/../lib/scala-library.jar
  file:/C:/DEVELO~1/scala/SCALA-~1.1/bin/../lib/scala-swing.jar
  file:/C:/DEVELO~1/scala/SCALA-~1.1/bin/../lib/scalap.jar
  file:/C:/temp/
)

null

因此系统类加载器保持不变,但 Scala 类加载器从 -cp 中获取添加到其中的项目。

这个故事的寓意:如果您想从类路径访问资源,请不要使用 Scala 中的系统类加载器。

编辑:好的,我对此进行了更多研究,scala.bat 正在执行以下命令行(在纯 Windows 下,为了便于阅读而缩短)

java.exe -Xmx256M -Xms32M -Dscala.home="xxx" -cp "libsfromscalahome" scala.tools.nsc.MainGenericRunner  -cp /temp Test

因此,命令行中的 -cp 选项仅作为选项传递给 MainGenericRunner,而不是 java.lang.我相信,通过查看代码,在 unix 下,您可以为 scala 指定 -toolcp 选项,以获取包含在 java 类路径中的内容。像这样的东西(完全未经测试):

$ scala -toolcp /temp Test

此选项在 scala.bat 中不可用。这意味着如果您在 Windows 下工作,则必须使用

获取资源
println(this.getClass.getClassLoader.getResource("toto"))

我在 Scala Lang Issues 中找不到问题,但如果这对您来说是个问题,请提出问题并提交修复。我相信他们会很兴奋:-)

编辑:我已将此作为问题提出 SI 5062 -toolcp should be available on windows, in the scala.bat ,并在 github 上提供了一个拉取请求。 .

关于scala 类加载器困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7671888/

相关文章:

java - 如何控制哪个 ClassLoader 加载类?

tomcat6 - Web 应用程序 WAR 文件中包含的自定义 Tomcat Valve

scala - Shapeless:将具有某些选项的元组映射到options

scala - 如何在 Scala 中将 DataFrame 导出到 csv?

scala - 为什么Spark的 “Detected cartesian product for INNER join between logical plans”失败?

excel - 如何将 apache poi 工作簿转换为 Spark 数据框?

java - 多个ClassLoader如何从不同位置加载同名资源?

scala - Play 框架 JSON 转换器,如何使用递归路径 (jsPath)?

java - Tomcat 重新启动后 session JDBCStore 失败 java.lang.Class.forName NullPointerException - 但只有一分钟左右,然后工作

使用 log4j 自定义布局类运行应用程序时,jBoss 上出现 java.lang.LinkageError