2011-10-06 61 views
9

请考虑下面的测试程序(使用Scala的2.9.0.1)Scala的类加载器的混乱

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中的一个(大)错误?!

谢谢, 阿琼

回答

11

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

说明返回该类的类加载器。一些实现可能使用 null来表示引导类加载器。如果此类由引导程序 类加载器加载,则此方法将在此类实现中返回 null。

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

第一个null很难解释。看起来Scala离开了系统类加载器,只是将选项-cp添加到它自己的类加载器(scalaClassLoader in scala/util/ClassLoader.scala)中。

使用下列内容:

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

,并运行它:

$ scala -cp /temp Test 

我们得到以下的输出:

[email protected] 
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 classloader从-cp中添加项目。

道德故事:如果您想从类路径访问资源,请不要在Scala中使用系统类加载器。

编辑:好吧,我已经调查了这一点,和斯卡拉。蝙蝠正在执行下面的命令行(在纯粹的Windows,缩短了可读性)

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

因此,从命令行-cp选项只被作为一个选项MainGenericRunner通过, java的。我相信,从查看代码,在unix下,您可以指定-toolcp选项以scala来获取java classpath中包含的内容。类似(完全未经测试):

$ 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它。

0

Wikipedia's classloader article

上java.class.path发现的系统,类加载器加载的代码,这 映射到系统CLASSPATH变量。

虽然不确定第二个null。也许别人可以清除那个。