请考虑以下测试程序(使用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/