scala classloaders混乱

时间:2011-10-06 08:30:44

标签: 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类没有classloader!

我在那里遗漏了什么,或者它是scala中的(大)错误?!

谢谢, 阿琼

2 个答案:

答案 0 :(得分:11)

第二个空值由java.lang.Class#getClassLoader()

解释
  

返回类的类加载器。一些实现可能会使用   null表示引导类加载器。这个方法会返回   如果此类由引导程序加载,则在此类实现中为null   类加载器。

因此,这就是classOf[Object].getClassLoader返回null的原因,它由引导程序类加载器加载(它位于rt.jar中,更具体地说,它位于$ JAVA_HOME / lib中的jar中)。

第一个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

因此System类加载器保持不变,但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。我相信,通过查看代码,在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上提供了拉取请求。

答案 1 :(得分:0)

来自Wikipedia's classloader article

  

系统类加载器加载在java.class.path上找到的代码   映射到系统CLASSPATH变量。

不确定第二个null。也许其他人可以清除它。