Почему Java 9 не просто превращает все JAR на пути к классам в автоматические модули?
Для того, чтобы понять категории у нас есть:
- явные модули платформы
- явные модули приложения
открытые модули- автоматические модули
- неназванный модуль
Все классы и фляги в пределах classpath будут частью неназванного модуля. Но почему это то, что нам нужно? Где преимущество перед автоматическими модулями? Я мог бы "потребовать" этих чертовых устаревших фляг, чтобы превратить их в автоматический модуль. Разве я не включил все это?
1 ответ
Есть как минимум две причины:
- Так же, как и обычные модули, автоматические модули подозреваются для определенных проверок системой модулей, например, не для разделения пакетов. Поскольку JAR-файлы на пути к классам могут (и иногда делают) разделять пакеты, навязывание этой проверки будет несовместимо с предыдущими версиями и нарушит работу ряда приложений.
- Безымянный модуль может читать все модули платформы, тогда как автоматические модули могут читать только те, которые попали в граф модулей. Это означает, что JAR, для которого требуется модуль java.desktop (например), будет работать из пути к классу, но не из графа модуля, если только java.desktop также не попадет в граф (через зависимость или
--add-modules
).
Сейчас у меня нет времени проверять второе, но вот что говорит система "Состояние модуля":
Следовательно, после того, как граф модулей разрешен, создается автоматический модуль для чтения любого другого названного модуля, будь то автоматический или явный
Разрешение работает на заявленных зависимостях, а автоматические модули не объявляют ни одного.
Помимо элементов, перечисленных в принятом ответе, есть еще одно отличие: безымянные модули могут получить доступ ко всем пакетам модулей, которые поставляются с Java, даже если они не экспортируются. Пока класс является общедоступным, доступ будет работать - так же, как и до Java 9. Но как только jar будет запущен из пути к модулю, он сможет получить доступ только к экспортированным пакетам.
Например, если некоторые .jar
имеет этот код:
com.sun.jmx.remote.internal.ArrayQueue c = new com.sun.jmx.remote.internal.ArrayQueue(10);
он будет работать нормально без каких-либо предупреждений при размещении в пути к классу, но при запуске из пути к модулю (как автоматический модуль) он завершится ошибкой во время выполнения:
Exception in thread "main" java.lang.IllegalAccessError: class test1.C
(in module test1) cannot access class com.sun.jmx.remote.internal.ArrayQueue
(in module java.management) because module java.management does not export
com.sun.jmx.remote.internal to module test1
Обратите внимание, что это отличается от хорошо известного предупреждения о незаконном отражении доступа, которое касается использования отражения для доступа к закрытым полям или методам. Здесь мы статически (без рефлексии) получаем доступ к общедоступному классу (но из неэкспортированного пакета).