#scala #classloader
#scala #загрузчик классов
Вопрос:
Пожалуйста, рассмотрите следующую тестовую программу (с использованием 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)
}
}
Я компилирую его и запускаю с помощью «-cp / tmp», содержащего файл «toto», и получаю следующий результат:
null
file:/tmp/toto
null
=> системный загрузчик классов не содержит пути к классу
=> класс Object не имеет загрузчика классов!
Я что-то упускаю или это (большая) ошибка в scala ?!
Спасибо, Арджун
Ответ №1:
Второй нуль объясняется java.lang.Class#getClassLoader()
Возвращает загрузчик класса для класса. Некоторые реализации могут использовать null для представления загрузчика классов начальной загрузки. Этот метод вернет null в таких реализациях, если этот класс был загружен загрузчиком классов bootstrap.
Итак, вот почему classOf[Object].getClassLoader
возвращает null, он загружается загрузчиком классов начальной загрузки (он находится в rt.jar , более конкретно, он находится в jar, который находится в $JAVA_HOME/lib).
Первый null объяснить сложнее. Кажется, что Scala оставляет системный загрузчик классов как есть и только добавляет options -cp к своему собственному загрузчику классов (ScalaClassLoader в 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
мы получаем следующий вывод:
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. Я полагаю, глядя на код, что в unix вы можете указать параметр -toolcp для scala, чтобы получить что-то включенное в путь к классу java. Что-то вроде (полностью непроверенный):
$ scala -toolcp /temp Test
Эта опция недоступна в scala.bat. Это означает, что если вы работаете под Windows, вам придется получать ресурсы с помощью
println(this.getClass.getClassLoader.getResource("toto"))
Я не смог найти проблему в проблемах Scala Lang, но если это проблема для вас, поднимите проблему и отправьте исправление. Я уверен, что они будут в восторге 🙂
РЕДАКТИРОВАТЬ: я поднял этот вопрос как проблему SI 5062 -toolcp должен быть доступен в Windows, в scala.bat, и предоставил запрос на извлечение для него на github.
Ответ №2:
Из статьи загрузчика классов в Википедии:
Загрузчик системных классов загружает код, найденный в java.class.path, который сопоставляется с системной переменной CLASSPATH.
Не уверен насчет второго нуля. Может быть, кто-то еще может это прояснить.