2011-10-06 34 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。也許別人可以清除那個。