Package info java: IBM Knowledge Center Error
Java. Экспресс-курс: Пакеты
Статья проплачена кошками — всемирно известными производителями котят.
Если статья вам понравилась, то можете поддержать проект.
Пакет является специальным библиотечным модулем, который содержит группу классов, объединённых в одном пространстве имён. Например, существует системная библиотека android.widget, в состав которой входит класс Button. Чтобы использовать класс в программе, можно привести его полное имя android.widget.Button. Но длинные имена классов не слишком удобно использовать в коде, поэтому можно использовать ключевое слово import.
import android.widget.Button;
Теперь к классу Button можно обращаться без указания полного имени.
Использование механизма импортирования обеспечивает возможность управления пространствами имён. Предположим, что вы создали класс Cat со своим набором методов, а кто-то другой тоже создал класс с подобным именем и со своим набором методов. Если вы захотите использовать свой и чужой класс в своей программе, то возникнет конфликт имён, так как Java не сможет понять, какой класс нужно использовать для вызова метода.
Файл с исходным кодом на Java является компилируемым модулем. Имя модуля имеет расширение java, а внутри него может находиться открытый (public) класс с именем файла без расширения. Модуль может содержать один открытый класс, остальные классы не должны быть открытыми и считаются вспомогательными по отношению к главному открытому классу.
Как уже говорилось, библиотека является набором файлов с классами. Директива package должна находиться в первой незакоментированной строке файла. По правилам Java имена пакетов записываются только строчными буквами. Все классы, находящиеся внутри данного файла, будут принадлежать указанному пакету. Если оператор package не указан, то имена классов помещаются в специальный пакет без имени. Но вы должны всячески избегать подобных ситуаций.
Указывать один и тот же пакет можно в разных файлах, он просто указывает кому принадлежит класс. Поэтому, если три разных класса в трёх разных файлах указывают на один и тот же package, то это нормально.
Можно создавать иерархию пакетов через точечный оператор:
package pack1[.pack2[.pack3]]; // например package cat.body.tail;
Создание уникальных имён пакетов
Существует общепринятая схема, где первая часть имени пакета должна состоять из перевёрнутого доменного имени разработчика класса. Так как доменные имена в интернете уникальны, соблюдение этого правила обеспечивает уникальность имён пакетов и предотврати конфликты. Если у вас нет собственного доменного имени, то придумайте свою уникальную комбинацию с малой вероятностью повторения.
Доступ к членам класса
Модификаторы обеспечивают различные уровни доступа к членам класса. Пакеты также вносят свою лепту. Можно представить себе такую таблицу.
private | Модификатор не указан | protected | public | |
---|---|---|---|---|
В том же классе | Да | Да | Да | Да |
Подкласс класса этого же пакета | Нет | Да | Да | Да |
Класс из общего пакета, не являющийся подклассом | Нет | Да | Да | Да |
Подкласс класса другого пакета | Нет | Нет | Да | Да |
Класс другого пакета, не являющий подклассом класса данного пакета | Нет | Нет | Нет | Да |
Любой компонент, объявленный как public, будет доступен из любого места. Компонент, объявленный как private, не виден для компонентов, расположенных вне его класса. Если модификатор явно не указан, он видим подклассам и другим классам в данном пакете. Это стандартное поведение по умолчанию. Если нужно, чтобы компонент был видим за пределами текущего пакета, но только классам, которые являются непосредственными подклассами данного класса, то используйте protected.
Это справедливо только для членов класса. У класса можно указать только два варианта: по умолчанию (не указан) и public.
Скорее всего в Android вам не придётся иметь дело с пакетами вплотную.
Импорт
В начале статьи я говорил вам, что импорт позволяет сократить написание полного имени класса. Он создан для удобства программистов и программа может обойтись из без него. Но если не выпендриваться и использовать импорт, то вы сократите уменьшите объём вводимого кода.
Оператор import должен идти сразу после оператора package (если он есть). Кстати, имя класса можно указать явно или с помощью символа «звёздочка» (*):
import java.io.*;
Но в Android такой способ категорически не рекомендуется использовать, так как ведёт к большому потреблению ресурсов. Да и сам я не разу не видел такой способ в примерах.
Таким образом, стандартный вариант:
public class MainActivity extends Activity {}
Можно заменить на вариант, удалив строчку кода из импорта:
public class MainActivity extends android.app.Activity {}
Дополнительные сведения об импорте.
Создание пакета
В студии создать пакет можно двумя способами. Первый — традиционный, щёлкаем правой кнопкой мыши на папке java или на существующем пакете и выбираем в меню команду New | Package.
Второй способ более хитрый — когда вы создаёте в студии новый класс, то указывая его имя можете использовать точечную нотацию, например, database.CatDB. В этом случае пакет database будет создан автоматически и в нём будет находиться создаваемый класс.
Реклама
Переход с Java 8 на Java 11 — Azure
-
- Чтение занимает 15 мин
-
В этой статье
Для перехода с Java 8 на Java 11 не существует универсального решения.There’s no one-size-fits-all solution to transition code from Java 8 to Java 11.
Переход нетривиального приложения с Java 8 на Java 11 может быть трудоемким процессом.For a non-trivial application, moving from Java 8 to Java 11 can be a significant amount of work. К потенциальным проблемам относятся удаленные API, устаревшие пакеты, использование внутреннего API, изменения в загрузчиках классов, а также изменения в сборке мусора. Potential issues include removed API, deprecated packages, use of internal API, changes to class loaders, and changes to garbage collection.
В целом, подходы заключаются в попытке запуска на Java 11 без перекомпиляции, или с начальной компиляцией с JDK 11.In general, the approaches are to try to run on Java 11 without recompiling, or to compile with JDK 11 first. Если цель состоит в том, чтобы запустить приложение как можно быстрее, то зачастую лучшим подходом является попытка запустить приложение на Java 11.If the goal is to get an application up and running as quickly as possible, just trying to run on Java 11 is often the best approach. Для библиотеки целью будет публикация артефакта, который компилируется и тестируется с помощью JDK 11.For a library, the goal will be to publish an artifact that is compiled and tested with JDK 11.
Переход на Java 11 трудозатратный.Moving to Java 11 is worth the effort. После выхода Java 8 было добавлено много новых функций и улучшений.New features have been added and enhancements have been made since Java 8. Эти функции и усовершенствования улучшают запуск, производительность, использование памяти и обеспечивают лучшую интеграцию с контейнерами.These features and enhancements improve startup, performance, memory usage, and provide better integration with containers. Кроме того в API добавлены дополнения и изменения, повышающие производительность разработчиков.And there are additions and modifications to API that improve developer productivity.
Этот документ касается средств для проверки кода.This document touches on tools to inspect code. Здесь также рассматриваются проблемы, с которыми вы можете столкнуться, и рекомендации по их устранению.It also covers issues that you may run into and recommendations for resolving them. Вам также следует принять во внимание другие руководства, такие как Oracle JDK Migration Guide (Руководство по миграции Oracle JDK).You should also consult other guides, such as the Oracle JDK Migration Guide. В этом руководстве не обсуждается вопрос изменения существующего кода на модулярный. How to make existing code modular is not covered here.
В Java 11 есть два инструмента, jdeprscan и jdeps, полезные при выявлении потенциальных проблем.Java 11 has two tools, jdeprscan and jdeps, that are useful for sniffing out potential issues. Эти инструменты можно запустить в существующих классах или JAR-файлах.These tools can be run against existing class or jar files. Вы можете оценить усилия для перехода, не нуждаясь в выполнении перекомпиляции.You can assess the transition effort without having to recompile.
jdeprscan ищет варианты использования нерекомендуемого или удаленного API.jdeprscan looks for use of deprecated or removed API.
Использование нерекомендуемого API не является блокирующей проблемой, однако на него следует обратить внимание.Use of deprecated API is not a blocking issue, but is something to look into. У вас есть обновленный JAR-файл?Is there an updated jar file? Нужно ли заносить проблему в журнал, чтобы решить проблему использования нерекомендуемого API?Do you need to log an issue to address the use of deprecated API? Использование удаленного API — это блокирующая проблема, которую необходимо решить до попытки запуска на Java 11. Use of removed API is a blocking issue that has to be addressed before you try to run on Java 11.
jdeps, представляющий собой анализатор зависимости от класса Java.jdeps, which is a Java class dependency analyzer. При использовании с опцией --jdk-internals
, jdeps сообщает, от которого внутреннего API зависит каждый класс.When used with the --jdk-internals
option, jdeps tells you which class depends on which internal API. Вы можете продолжать использовать внутренний API на Java 11, однако приоритетом должна стать замена потребления.You can continue to use internal API in Java 11, but replacing the usage should be a priority. На вики-странице OpenJDK Java Dependency Analysis Tool (Средство анализа зависимости от класса Java) содержатся рекомендуемые замены для некоторых широко используемых внутренних API для JDK.The OpenJDK wiki page Java Dependency Analysis Tool has recommended replacements for some commonly used JDK internal APIs.
Для Gradle и Maven есть подключаемые модули jdeps и jdeprscan. There are jdeps and jdeprscan plugins for both Gradle and Maven. Мы рекомендуем добавить эти инструменты в ваши скрипты сборки.We recommend adding these tools to your build scripts.
Сам компилятор Java, javac, является еще одним инструментом в вашем инструментарии.The Java compiler itself, javac, is another tool in your toolbox. Предупреждения и ошибки, которые вы получите от jdeprscan и jdeps, будут выдаваться компилятором.The warnings and errors you get from jdeprscan and jdeps will come out of the compiler. Преимущество использования jdeprscan и jdeps заключается в том, что вы можете запускать эти инструменты поверх существующих файлов JAR и файлов классов, включая сторонние библиотеки.The advantage of using jdeprscan and jdeps is that you can run these tools over existing jars and class files, including third-party libraries.
Что jdeprscan и jdeps не могут сделать, так это предупредить об использовании отражения для доступа к инкапсулированному API. What jdeprscan and jdeps cannot do is warn about the use of reflection to access encapsulated API. Доступ с помощью рефлексии проверяется во время выполнения.Reflective access is checked at runtime. Безусловно, чтобы быть уверенным, код следует запустить на Java 11.Ultimately, you have to run the code on Java 11 to know with certainty.
Использование jdeprscanUsing jdeprscan
Самый простой способ использовать jdeprscan — предоставить ему JAR-файл из существующей сборки.The easiest way to use jdeprscan is to give it a jar file from an existing build. Ему можно также предоставить каталог, например выходной каталог компилятора или имя отдельного класса.You can also give it a directory, such as the compiler output directory, or an individual class name. Используйте параметр --release 11
, чтобы получить наиболее полный список нерекомендуемых API.Use the --release 11
option to get the most complete list of deprecated API. Если вы хотите определить, какой из нерекомендуемых API следует использовать, снова верните для параметра значение --release 8
. If you want to prioritize which deprecated API to go after, dial the setting back to --release 8
. API, признанный нерекомендуемым на Java 8, скорее всего, будет удален раньше, чем API, признанный нерекомендуемым совсем недавно.API that was deprecated in Java 8 is likely to be removed sooner than API that has been deprecated more recently.
jdeprscan --release 11 my-application.jar
Инструмент jdeprscan генерирует сообщение об ошибке при возникновении проблем с разрешением зависимого класса.The jdeprscan tool generates an error message if it has trouble resolving a dependent class.
Например, error: cannot find class org/apache/logging/log4j/Logger
.For example, error: cannot find class org/apache/logging/log4j/Logger
. Рекомендуется добавлять зависимые классы в --class-path
или использовать путь класса приложения, однако инструмент продолжит сканирование без него.Adding dependent classes to the --class-path
or using the application class-path is recommended, but the tool will continue the scan without it.
Аргументом является ‑‑class‑path.The argument is ‑‑class‑path. Никакие другие вариации аргумента пути класса не сработают.No other variations of the class-path argument will work.
jdeprscan --release 11 --class-path log4j-api-2.13.0.jar my-application.jar
error: cannot find class sun/misc/BASE64Encoder
class com/company/Util uses deprecated method java/lang/Double::<init>(D)V
Этот вывод говорит о том, что класс com.company.Util
вызывает нерекомендуемый конструктор класса java.lang.Double
.This output tells us that the com.company.Util
class is calling a deprecated constructor of the java.lang.Double
class. javadoc порекомендует, какой API следует использовать вместо нерекомендуемого.The javadoc will recommend API to use in place of deprecated API. Никакой объем работы не решит error: cannot find class sun/misc/BASE64Encoder
, поскольку это API, который был удален.No amount of work will resolve the error: cannot find class sun/misc/BASE64Encoder
because it is API that has been removed. Начиная с Java 8, следует использовать java.util.Base64
.Since Java 8, java.util.Base64
should be used.
Запустите jdeprscan --release 11 --list
, чтобы получить представление о том, какие API стали нерекомендуемыми после Java 8.Run jdeprscan --release 11 --list
to get a sense of what API has been deprecated since Java 8. Чтобы получить список удаленных API, запустите jdeprscan --release 11 --list --for-removal
.To get a list of API that has been removed, run jdeprscan --release 11 --list --for-removal
.
Использование jdepsUsing jdeps
Используйте jdeps, с опцией --jdk-internals
, что найти зависимости от внутреннего API для JDK.Use jdeps, with the --jdk-internals
option to find dependencies on JDK internal API. Для этого примера нужен параметр командной строки --multi-release 11
, поскольку log4j-core-2.13.0.jar является JAR-файлом с несколькими выпусками. The command line option --multi-release 11
is needed for this example because log4j-core-2.13.0.jar is a multi-release jar file. Без этой опции при нахождении JAR-файла с несколькими выпусками jdeps будет создавать предупреждение.Without this option, jdeps will complain if it finds a multi-release jar file. Параметр определяет, какую версию файлов классов необходимо проверить.The option specifies which version of class files to inspect.
jdeps --jdk-internals --multi-release 11 --class-path log4j-core-2.13.0.jar my-application.jar
Util.class -> JDK removed internal API
Util.class -> jdk.base
Util.class -> jdk.unsupported
com.company.Util -> sun.misc.BASE64Encoder JDK internal API (JDK removed internal API)
com.company.Util -> sun.misc.Unsafe JDK internal API (jdk.unsupported)
com.company.Util -> sun.nio.ch.Util JDK internal API (java.base)
Warning: JDK internal APIs are unsupported and private to JDK implementation that are
subject to be removed or changed incompatibly and could break your application.
Please modify your code to eliminate dependence on any JDK internal APIs.
For the most recent update on JDK internal API replacements, please check:
https://wiki.openjdk.java.net/display/JDK8/Java+Dependency+Analysis+Tool
JDK Internal API Suggested Replacement
---------------- ---------------------
sun.misc.BASE64Encoder Use java.util.Base64 @since 1.8
sun.misc.Unsafe See http://openjdk.java.net/jeps/260
Выход дает несколько хороших советов по устранению использования внутреннего API JDK.The output gives some good advice on eliminating use of JDK internal API! Замена API предлагается на всех возможных местах.Where possible, the replacement API is suggested. В скобках указано имя модуля, в котором инкапсулирован пакет.The name of the module where the package is encapsulated is given in the parentheses. Имя модуля можно использовать с --add-exports
или --add-opens
, если необходимо явно прервать инкапсуляцию. The module name can be used with --add-exports
or --add-opens
if it is necessary to explicitly break encapsulation.
Использование sun.misc.BASE64Encoder или sun.misc.BASE64Decoder приведет на Java 11 к ошибке java.lang.NoClassDefFoundError.The use of sun.misc.BASE64Encoder or sun.misc.BASE64Decoder will result in a java.lang.NoClassDefFoundError in Java 11. Использующий эти API код следует модифицировать для использования java.util.Base64.Code that uses these APIs has to be modified to use java.util.Base64.
Попробуйте исключить использование любых API, исходящих из модуля jdk.unsupported.Try to eliminate the use of any API coming from the module jdk.unsupported. API из этого модуля будет ссылаться на Предложение по усовершенствованию JDK (JEP) 260 в качестве предлагаемой замены.API from this module will reference JDK Enhancement Proposal (JEP) 260 as a suggested replacement.
Если кратко, то JEP 260 говорит, что использование внутреннего API будет поддерживаться до тех пор, пока не будет доступен заменяющий API.In a nutshell, JEP 260 says that the use of internal API will be supported until replacement API is available. Несмотря на то, что ваш код может использовать внутренний API для JDK, он будет продолжать работать, по крайней мере, некоторое время.Even though your code may use JDK internal API, it will continue to run, for a while at least. Взгляните на JEP 260, так как он указывает на замену некоторых внутренних API.Do take a look at JEP 260 since it does point to replacements for some internal API.
переменные дескрипторы можно использовать, например, вместо некоторых API sun.misc.Unsafe.variable handles can be used in place of some sun.misc.Unsafe API, for example.
jdeps может сделать нечто большее, чем просто проверить использование внутренних компонентов JDK.jdeps can do more than just scan for use of JDK internals. Это полезный инструмент для анализа зависимостей и создания файлов сведений о модуле.It is a useful tool for analyzing dependencies and for generating a module-info files. Дополнительные сведения можно найти в документации.Take a look at the documentation for more.
Использование javacUsing javac
Компиляция с JDK 11 потребует обновлений для сборки скриптов, инструментов, тестовых платформ и включенных библиотек.Compiling with JDK 11 will require updates to build scripts, tools, test frameworks, and included libraries. Используйте параметр -Xlint:unchecked
для javac, чтобы получить подробные сведения об использовании внутреннего API JDK и других предупреждений.Use the -Xlint:unchecked
option for javac to get the details on use of JDK internal API and other warnings. Также для демонстрации компилятору инкапсулированных пакетов может потребоваться использование --add-opens
или --add-reads
(см. JEP 261).It may also be necessary to use --add-opens
or --add-reads
to expose encapsulated packages to the compiler (see JEP 261).
Библиотеки могут рассматривать упаковку как JAR-файл с несколькими выпусками.Libraries can consider packaging as a multi-release jar file. JAR-файлы с несколькими выпусками позволяют поддерживать среды выполнения как Java 8, так и Java 11 из одного и того же JAR-файла.Multi-release jar files allow you to support both Java 8 and Java 11 runtimes from the same jar file. Они действительно добавляют сложность в выполнение сборки.They do add complexity to the build. Сведения о сборке JAR-файлов с несколькими выпусками не входят в область, рассматриваемую эти документом.How to build multi-release jars is beyond the scope of this document.
Выполнение на Java 11Running on Java 11
Большинство приложений должно работать на Java 11 без необходимости в изменениях.Most applications should run on Java 11 without modification. Первое, что нужно попробовать — это запустить Java 11 без перекомпиляции кода.The first thing to try is to run on Java 11 without recompiling the code. Смысл простого запуска заключается в том, чтобы посмотреть, какие предупреждения и ошибки будут выданы во время выполнения. The point of just running is to see what warnings and errors come out of the execution. При таком подходеThis approach gets an
приложение работает на Java 11 быстрее, сосредоточившись на минимуме, который необходимо сделать.application to run on Java 11 more quickly by focusing on the minimum that needs to be done.
Большинство проблем, с которыми вы можете столкнуться, можно решить, не выполняя перекомпиляцию кода.Most of the problems you may encounter can be resolved without having to recompile code.
Если проблему следует исправлять в коде, исправьте ее, но продолжайте компилировать с помощью JDK 8.If an issue has to be fixed in the code, then make the fix but continue to compile with JDK 8. По возможности работайте над доведением приложения до запуска с java
версией 11 до компиляции с JDK 11.If possible, work on getting the application to run with java
version 11 before compiling with JDK 11.
Проверка параметров командной строкиCheck command line options
Перед выполнением на Java 11 следует выполнить быструю проверку параметров командной строки. Before running on Java 11, do a quick scan of the command-line options.
Удаленные опции приведут к выходу виртуальной машины Java.Options that have been removed will cause the Java Virtual Machine (JVM) to exit. Эта проверка особенно важна, если вы используете опции ведения журнала для сборки мусора, поскольку они радикально изменились с Java 8.This check is especially important if you use GC logging options since they have changed drastically from Java 8. Инструмент JaCoLine хорошо подходит для обнаружения проблем с параметрами командной строки.The JaCoLine tool is a good one to use to detect problems with the command line options.
Проверка сторонних библиотекCheck third-party libraries
Потенциальным источником проблем являются сторонние библиотеки, которые вы не контролируете.A potential source of trouble is third-party libraries that you don’t control. Вы можете заблаговременно обновлять сторонние библиотеки до более новых версий.You can proactively update third-party libraries to more recent versions. Или посмотреть, что выходить за пределы выполнения приложения и обновить только нужные библиотеки.Or you can see what falls out of running the application and only update those libraries that are necessary. Проблема с обновлением всех библиотек до последней версии заключается в том, что это затрудняет поиск первопричины появления в приложении ошибки.The problem with updating all libraries to a recent version is that it makes it harder to find root cause if there is some error in the application. Ошибка произошла из-за какой-то обновленной библиотеки?Did the error happen because of some updated library? Или ошибка была вызвана каким-то изменением в среде выполнения?Or was the error caused by some change in the runtime? Проблема обновления связана только с тем, что для ее решения может потребоваться несколько итераций.The problem with updating only what’s necessary is that it may take several iterations to resolve.
Рекомендуется вносить как можно меньше изменений и обновлять сторонние библиотеки в виде отдельных трудозатрат. The recommendation here is to make as few changes as possible and to update third-party libraries as a separate effort. Если вы обновляете стороннюю библиотеку, то чаще всего вам потребуется самая последняя версия, совместимая с Java 11.If you do update a third-party library, more often than not you will want the latest-and-greatest version that is compatible with Java 11. В зависимости от того, насколько отстает ваша текущая версия, возможно, вы захотите применить более осторожный подход и обновить ее до первой версии, совместимой с Java 9+.Depending on how far behind your current version is, you may want to take a more cautious approach and upgrade to the first Java 9+ compatible version.
Кроме просмотра заметок о выпуске, для оценки JAR-файла можно использовать jdeps и jdeprscan.In addition to looking at release notes, you can use jdeps and jdeprscan to assess the jar file. Кроме того, Группа контроля качества OpenJDK поддерживает вики-страницу Quality Outreach (Популяризация качественного содержимого), на которой перечислен статус тестирования многих проектов FOSS с версиями OpenJDK. Also, the OpenJDK Quality Group maintains a Quality Outreach wiki page that lists the status of testing of many Free Open Source Software (FOSS) projects against versions of OpenJDK.
Явно установленная сборка мусораExplicitly set garbage collection
Сборщик мусора Parallel (Parallel GC) — это стандартный сборщик мусора в Java 8.The Parallel garbage collector (Parallel GC) is the default GC in Java 8. Если приложение использует значение по умолчанию, сборку мусора следует явно задать с помощью параметра командной строки -XX:+UseParallelGC
.If the application is using the default, then the GC should be explicitly set with the command-line option -XX:+UseParallelGC
.
Вместо значения по умолчанию в Java 9 используется сборщик мусора G1GC (Garbage First Garbage Collector).The default changed in Java 9 to the Garbage First garbage collector (G1GC). Чтобы справедливо сравнить приложение, работающее на Java 8, с Java 11, настройки сборки мусора должны быть одинаковыми. In order to make a fair comparison of an application running on Java 8 versus Java 11, the GC settings must be the same. Экспериментирование с настройками сборки мусора следует отложить, пока приложение не будет проверено на Java 11.Experimenting with the GC settings should be deferred until the application has been validated on Java 11.
Явно заданные параметры по умолчаниюExplicitly set default options
При запуске на ВМ HotSpot, установка параметра командной строки -XX:+PrintCommandLineFlags
будет сбрасывать значения параметров, установленных ВМ, в частности, значения по умолчанию, установленные сборкой мусора.If running on the HotSpot VM, setting the command line option -XX:+PrintCommandLineFlags
will dump the values of options set by the VM, particularly the defaults set by the GC.
Запускайте с этим флагом на Java 8 и используйте печатные параметры при запуске на Java 11.Run with this flag on Java 8 and use the printed options when running on Java 11. По большей части, значения по умолчанию для версий от 8 до 11 одинаковы.For the most part, the defaults are the same from 8 to 11. Но использование настроек из 8 обеспечивает четность.But using the settings from 8 ensures parity.
Рекомендуется использовать параметр командной строки --illegal-access=warn
.Setting the command line option --illegal-access=warn
is recommended.
Использование рефлексии для доступа к внутреннему API для JDK в Java 11 приведет к появлению предупреждения о недопустимом доступе с помощью рефлексии.In Java 11, using reflection to access to JDK-internal API will result in an illegal reflective access warning.
По умолчанию предупреждение выдается только при первом недопустимом доступе.By default, the warning is only issued for the first illegal access. Установка --illegal-access=warn
приведет к вызову предупреждения при каждом недопустимом доступе с помощью рефлексии.Setting --illegal-access=warn
will cause a warning on every illegal reflective access. Установив параметр на предупреждение, вы сможете найти еще больше случаев недопустимого доступа.You will find more case if illegal access with the option set to warn. Но вы также будете получать много лишних предупреждений.But you will also get a lot of redundant warnings.
После запуска приложения на Java 11, установите --illegal-access=deny
для имитации будущего поведения во время выполнения Java.Once the application runs on Java 11, set --illegal-access=deny
to mimic the future behavior of the Java runtime. Начиная с Java 16, значением по умолчанию будет --illegal-access=deny
.Starting with Java 16, the default will be --illegal-access=deny
.
Предостережения ClassLoaderClassLoader cautions
В Java 8 загрузчик системного класса можно привести к URLClassLoader
.In Java 8, you can cast the system class loader to a URLClassLoader
. Обычно это выполняется приложениями и библиотеками, которые хотят внедрить классы в путь к классу во время выполнения. This is usually done by applications and libraries that want to inject classes into the classpath at runtime. В Java 11 иерархия классов загрузчиков изменилась.The class loader hierarchy has changed in Java 11. Загрузчик системного класса (также известный как загрузчик класса приложения) теперь является внутренним классом.The system class loader (also known as the application class loader) is now an internal class. Приведение к URLClassLoader
вызовет ClassCastException
во время выполнения.Casting to a URLClassLoader
will throw a ClassCastException
at runtime. Java 11 не имеет API для динамического дополнения пути к классу во время выполнения, но это можно сделать с помощью рефлексии, с очевидными предостережениями об использовании внутреннего API.Java 11 does not have API to dynamically augment the classpath at runtime but it can be done through reflection, with the obvious caveats about using internal API.
В Java 11 загрузчик класса загрузки загружает только основные модули. In Java 11, the boot class loader only loads core modules. При создании загрузчика классов с нулевым родительским элементом, он сможет найти не все классы платформы.If you create a class loader with a null parent, it may not find all platform classes. В Java 11 в таких случаях в качестве загрузчика класса родительского элемента нужно передавать ClassLoader.getPlatformClassLoader()
, а не null
.In Java 11, you need to pass ClassLoader.getPlatformClassLoader()
instead of null
as the parent class loader in such cases.
Изменения локальных данныхLocale data changes
Источник локальных данных по умолчанию на Java 11 изменен с помощью JEP 252 на Единый репозиторий локальных данных консорциума Юникод.The default source for locale data in Java 11 was changed with JEP 252 to the Unicode Consortium’s Common Locale Data Repository. Это может повлиять на локальное форматирование.This may have an impact on localized formatting. При необходимости установите системное свойство java. locale.providers=COMPAT,SPI
для возврата к поведению языкового стандарта Java 8.Set the system property java.locale.providers=COMPAT,SPI
to revert to the Java 8 locale behavior, if necessary.
Возможные проблемыPotential issues
Вот некоторые из общих проблем, с которыми вы можете столкнуться.Here are some of the common issues you might come across. Более подробные сведения по этим вопросам см. по ссылкам.Follow the links for more details about these issues.
Нераспознанные параметрыUnrecognized options
Если параметр командной строки удален, то приложение выведет Unrecognized option:
или Unrecognized VM option
, за которым последует имя конфликтующего параметра.If a command-line option has been removed, the application will print Unrecognized option:
or Unrecognized VM option
followed by the name of the offending option. Нераспознанный параметр приведет к выходу ВМ.An unrecognized option will cause the VM to exit.
Нерекомендуемые параметры, которые не были удалены, будут выдавать предупреждение ВМ.Options that have been deprecated, but not removed, will produce a VM warning.
В общем, удаленные параметры не заменяются, и единственным решением является удаление параметра из командной строки.In general, options that were removed have no replacement and the only recourse is to remove the option from the command line. Исключением являются опции для ведения журнала о сборе мусора.The exception is options for garbage collection logging. Ведение журнала о сборке мусора реализовано в Java 9 для использования унифицированной платформы ведения журналов JVM.GC logging was reimplemented in Java 9 to use the unified JVM logging framework. См. «Table 2-2 Mapping Legacy Garbage Collection Logging Flags to the Xlog Configuration» (Таблица 2-2. Сопоставление флагов ведения журнала устаревших сборок мусора с конфигурацией Xlog) в разделе Enable Logging with the JVM Unified Logging Framework (Включение ведения журнала с помощью унифицированной платформы ведения журналов JVM) из Справочника по инструментам Java SE 11. Refer to «Table 2-2 Mapping Legacy Garbage Collection Logging Flags to the Xlog Configuration» in the section Enable Logging with the JVM Unified Logging Framework of the Java SE 11 Tools Reference.
Предупреждения ВМVM warnings
Использование нерекомендуемых параметров приведет к созданию предупреждения.Use of deprecated options will produce a warning. Параметр становится нерекомендуемым, если он заменен или больше не используется.An option is deprecated when it has been replaced or is no longer useful. Как и в случае с удаленными параметрами, эти параметры следует удалить из командной строки.As with removed options, these options should be removed from the command line.
Предупреждение VM Warning: Option <option> was deprecated
означает, что параметр все еще поддерживается, но эта поддержка может быть удалена в будущем.The warning VM Warning: Option <option> was deprecated
means that the option is still supported, but that support may be removed in the future. Параметр, который больше не поддерживается, будет выдавать предупреждение VM Warning: Ignoring option
.An option that is no longer supported and will generate the warning VM Warning: Ignoring option
.
Неподдерживаемые параметры не влияют на среду выполнения.Options that are no longer supported have no effect on the runtime.
На веб-странице VM Options Explorer (Обозреватель параметров ВМ) представлен исчерпывающий список параметров, которые были добавлены в Java, начиная с JDK 7 или добавлены в него.The web page VM Options Explorer provides an exhaustive list of options that have been added to or removed from Java since JDK 7.
Ошибка: Не удалось создать виртуальную машину Java.Error: Could not create the Java Virtual Machine
Это сообщение об ошибке выводится, когда виртуальная машина Java сталкивается с нераспознанным параметром.This error message is printed when the JVM encounters an unrecognized option.
ПРЕДУПРЕЖДЕНИЕ. Возникла недопустимая операция доступа с помощью рефлексииWARNING: An illegal reflective access operation has occurred
Если Java-код использует отражение для доступа к внутреннему API JDK, во время выполнения будет выдано предупреждение о недопустимом доступе с помощью рефлексии. When Java code uses reflection to access JDK-internal API, the runtime will issue an illegal reflective access warning.
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by my.sample.Main (file:/C:/sample/) to method sun.nio.ch.Util.getTemporaryDirectBuffer(int)
WARNING: Please consider reporting this to the maintainers of com.company.Main
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
Это означает, что модуль не экспортировал пакет, доступ к которому осуществляется через отражение.What this means is that a module has not exported the package that is being accessed through reflection. Пакет инкапсулирован в модуль и по сути является внутренним API.The package is encapsulated in the module and is, basically, internal API. Предупреждение можно проигнорировать в качестве первого шага по установке и запуску Java 11. The warning can be ignored as a first effort to getting up and running on Java 11.
Время выполнения Java 11 разрешает доступ с помощью рефлексии, так что старый код может продолжать работу.The Java 11 runtime permits the reflective access so that legacy code can continue to work.
Чтобы решить это предупреждение, найдите обновленный код, который не использует внутренний API.To address this warning, look for updated code that does not make use of the internal API. Если проблему невозможно решить с помощью обновленного кода, для открытия доступа к пакету можно использовать либо параметр --add-exports
, либо параметр командной строки --add-opens
.If the issue cannot be resolved with updated code, either the --add-exports
or the --add-opens
command-line option can be used to open access to the package.
Эти параметры позволяют получить доступ к неэкспортированным типам одного модуля из другого.These options allow access to unexported types of one module from another module.
Параметр --add-exports
позволяет целевому модулю получить доступ к общедоступным типам именованного пакета модуля-источника.The --add-exports
option allows the target module to access the public types of the named package of the source module. Иногда для доступа к членам и API, не являющимся открытыми, код будет использовать setAccessible(true)
.Sometimes code will use setAccessible(true)
to access non-public members and API. Он известен, как глубокое отражение.This is known as deep reflection. В этом случае используйте --add-opens
для предоставления вашему коду доступа к членам пакета, которые не являются открытыми.In this case, use --add-opens
to give your code access to the non-public members of a package. Если вы не уверены, использовать —add-exports или —add-opens, начните с —add-exports.If you are unsure whether to use —add-exports or —add-opens, start with —add-exports.
Параметры --add-exports
или --add-opens
следует рассматривать как обходной путь, а не как долгосрочное решение.The --add-exports
or --add-opens
options should be considered as a work-around, not a long-term solution.
Использование этих опций прерывает инкапсуляцию модульной системы, которая должна препятствовать использованию внутреннего API JDK.Using these options breaks encapsulation of the module system, which is meant to keep JDK-internal API from being used. Если внутренний API будет удален или изменен, приложение выйдет из строя.If the internal API is removed or changes, the application will fail. Доступ с помощью рефлексии будет запрещен на Java 16, за исключением случаев, когда доступ будет разрешен параметрами командной строки, такими как --add-opens
.Reflective access will be denied in Java 16, except where access enabled by command line options such as --add-opens
.
Чтобы имитировать будущее поведение, установите --illegal-access=deny
в командной строке.To mimic the future behavior, set --illegal-access=deny
on the command line.
Предупреждение в приведенном выше примере выдается потому, что пакет sun.nio.ch
не экспортируется модулем java.base
.The warning in the example above is issued because the sun.nio.ch
package is not exported by the java.base
module. Другими словами, в файле module-info.java
модуля java.base
нет exports sun.nio.ch;
.In other words, there is no exports sun.nio.ch;
in the module-info.java
file of module java.base
. Это можно решить с помощью --add-exports=java.base/sun.nio.ch=ALL-UNNAMED
.This can be resolved with --add-exports=java.base/sun.nio.ch=ALL-UNNAMED
. Классы, не определенные в модуле, неявно принадлежат неименованному модулю, буквально названному ALL-UNNAMED
.Classes that are not defined in a module implicitly belong to the unnamed module, literally named ALL-UNNAMED
.
java.lang.reflect.InaccessibleObjectExceptionjava.lang.reflect.InaccessibleObjectException
Это исключение указывает на то, что вы пытаетесь вызвать setAccessible(true)
в поле, или метод инкапсулированного класса.This exception indicates that you are trying to call setAccessible(true)
on a field or method of an encapsulated class. Вы также можете получить предупреждение о недопустимом доступе с помощью рефлексии.You may also get an illegal reflective access warning. Используйте --add-opens
для предоставления вашему коду доступа к членам пакета, которые не являются открытыми.Use the --add-opens
option to give your code access to the non-public members of a package. Сообщение об исключении сообщит, что модуль «не открывает» пакет модулю, который пытается вызвать setAccessible.The exception message will tell you the module «does not open» the package to the module that is trying to call setAccessible. Если модуль является «неименованным», используйте UNNAMED-MODULE
в качестве целевого модуля в параметре —add-opens.If the module is «unnamed module», use UNNAMED-MODULE
as the target-module in the —add-opens option.
java.lang.reflect.InaccessibleObjectException: Unable to make field private final java.util.ArrayList jdk.internal.loader.URLClassPath.loaders accessible:
module java.base does not "opens jdk.internal.loader" to unnamed module @6442b0a6
$ java --add-opens=java.base/jdk.internal.loader=UNNAMED-MODULE example.Main
java.lang.NoClassDefFoundErrorjava.lang.NoClassDefFoundError
Ошибка NoClassDefFoundError, скорее всего, вызвана разделенным пакетом или ссылкой на удаленные модули.NoClassDefFoundError is most likely caused by a split package, or by referencing removed modules.
Ошибка NoClassDefFoundError, вызванная разделением пакетовNoClassDefFoundError caused by split-packages
Раздельный пакет —это пакет, находящийся в нескольких библиотеках.A split package is when a package is found in more than one library. Симптомом проблемы разделения пакетов является то, что класс, который должен находится в пути класса, невозможно найти.The symptom of a split-package problem is that a class you know to be on the class-path is not found.
Эта проблема будет возникать только при использовании пути модуля.This issue will only occur when using the module-path. Система модулей Java оптимизирует поиск классов, ограничивая пакет одним именованным модулем.The Java module system optimizes class lookup by restricting a package to one named module. При выполнении поиска классов предпочтение отдается пути модуля, а не класса.The runtime gives preference to the module-path over the class-path when doing a class lookup. Если пакет разделен между модулем и путем к классу, то для поиска класса используется только модуль.If a package is split between a module and the class-path, only the module is used to do the class lookup. Это может привести к ошибкам NoClassDefFound
.This can lead to NoClassDefFound
errors.
Простой способ проверки разделенного пакета — подключить путь к модулю и к классу в jdeps и использовать путь к файлам класса приложения в качестве значения <path>.An easy way to check for a split package is to plug your module path and class path into jdeps and use the path to your application class files as the <path>. Если есть разделенный пакет, jdeps выведет предупреждение: Warning: split package: <package-name> <module-path> <split-path>
.If there is a split package, jdeps will print out a warning: Warning: split package: <package-name> <module-path> <split-path>
.
Эту проблему можно решить, используя --patch-module <module-name>=<path>[,<path>]
для добавления разделенного пакета в именованный модуль.This issue can be resolved by using --patch-module <module-name>=<path>[,<path>]
to add the split package into the named module.
Ошибка NoClassDefFoundError, вызванная использованием модулей Java EE или CORBANoClassDefFoundError caused by using Java EE or CORBA modules
Если приложение работает на Java 8, но вызывает java.lang.NoClassDefFoundError
или java.lang.ClassNotFoundException
, то вполне вероятно, что приложение использует пакет из модулей Java EE или CORBA.If the application runs on Java 8 but throws a java.lang.NoClassDefFoundError
or a java.lang.ClassNotFoundException
, then it is likely that the application is using a package from the Java EE or CORBA modules. Эти модули признаны нерекомендуемыми на Java 9 и удалены на Java 11.These modules were deprecated in Java 9 and removed in Java 11.
Чтобы решить проблему, добавьте в проект зависимость среды выполнения.To resolve the issue, add a runtime dependency to your project.
-Xbootclasspath/p больше не поддерживается-Xbootclasspath/p is no longer a supported option
Поддержка для -Xbootclasspath/p
удалена.Support for -Xbootclasspath/p
has been removed. Используйте вместо этого --patch-module
.Use --patch-module
instead. Параметр —patch-module описан в JEP 261.The —patch-module option is described in JEP 261. Ищите раздел с названием «Patching module content» (Исправление содержимого модуля).Look for the section labeled «Patching module content». —patch-module можно использовать с javac и java для переопределения или дополнения классов в модуле.—patch-module can be used with javac and with java to override or augment the classes in a module.
Что делает —patch-module, так это вставляет модуль исправления в поиск класса модульной системы.What —patch-module does, in effect, is insert the patch module into the module system’s class lookup. Модульная система сначала захватит класс из модуля исправления.The module system will grab the class from the patch module first. Это тот же эффект, что и в случае с bootclasspath на Java 8.This is the same effect as pre-pending the bootclasspath in Java 8.
UnsupportedClassVersionErrorUnsupportedClassVersionError
Это исключение означает, что вы пытаетесь запустить код, который был скомпилирован с более поздней версией Java, на более ранней версии Java.This exception means that you are trying to run code that was compiled with a later version of Java on an earlier version of Java. Например, вы работаете на Java 11 с JAR-файлом, скомпилированным с JDK 13.For example, you are running on Java 11 with a jar that was compiled with JDK 13.
Версия JavaJava version | Версия формата файла классаClass file format version |
---|---|
88 | 5252 |
99 | 5353 |
1010 | 5454 |
1111 | 5555 |
1212 | 5656 |
1313 | 5757 |
Дальнейшие действияNext steps
После того, как приложение запустится на Java 11, рассмотрите возможность переноса библиотек с пути класса на путь модуля.Once the application runs on Java 11, consider moving libraries off the class-path and onto the module-path. Выполните поиск обновленных версий библиотек, от которых зависит ваше приложение.Look for updated versions of the libraries your application depends on. Если возможно, выбирайте модульные библиотеки.Choose modular libraries, if available. Используйте путь модулей, даже если вы не планируете использовать модули в своем приложении.Use the module-path as much as possible, even if you don’t plan on using modules in your application. Использование пути модуля предоставляет производительность при загрузке классов, которая намного лучше производительности при использовании пути модуля.Using the module-path has better performance for class loading than the class-path does.
IntelliJ не может распознать JavaFX 11 с OpenJDK 11
Вопрос:
У меня проблемы с тем, чтобы IntellJ распознавал пакеты JavaFX. В новом проекте JavaFX, в OpenJDK 11, при попытке создать проект IntelliJ не может распознать пакеты JavaFX.
Я импортировал openjfx:javafx-base-11
из openjfx:javafx-base-11
Maven.
Я смотрел на другие вопросы, и решения, кажется, варьируются от проверки того, что байт-код находится на правильном уровне (у меня есть), и что язык проекта правильный (у меня есть).
У кого-нибудь есть идеи?
Редактировать:
Ошибка:
Лучший ответ:
Как упоминалось в комментариях, Руководство по началу работы — это то место, с которого можно начинать с Java 11 и JavaFX 11.
Ключ к работе, как вы делали до Java 11, заключается в том, чтобы понять, что:
- JavaFX 11 больше не является частью JDK
- Вы можете получить его в разных вариантах, либо в виде SDK, либо как
регулярные зависимости (maven/gradle). - Вам нужно будет включить его в путь модуля вашего проекта, даже если ваш проект не является модульным.
Проект JavaFX
Если вы создаете обычный проект JavaFX по умолчанию в IntelliJ (без Maven или Gradle), я бы предложил вам загрузить SDK с здесь. Обратите внимание, что также существуют jmod, но для немодулярного проекта предпочтителен SDK.
Это простые шаги для запуска проекта по умолчанию:
- Создать проект JavaFX
- Установите JDK 11 (укажите на локальную версию Java 11)
- Добавьте JavaFX 11 SDK в качестве библиотеки. URL-адрес может быть что-то вроде
/Users/<user>/Downloads/javafx-sdk-11/lib/
. После этого вы заметите, что классы JavaFX теперь распознаются в редакторе.
Перед запуском проекта по умолчанию вам просто нужно добавить их в опции VM:
--module-path /Users/<user>/Downloads/javafx-sdk-11/lib --add-modules=javafx.controls,javafx.fxml
Запуск
Maven
Если вы используете Maven для создания своего проекта, выполните следующие действия:
- Создайте проект Maven с архетипом JavaFX
- Установите JDK 11 (укажите на локальную версию Java 11)
Добавьте зависимости JavaFX 11.
<dependencies> <dependency> <groupId>org.openjfx</groupId> <artifactId>javafx-controls</artifactId> <version>11</version> </dependency> <dependency> <groupId>org.openjfx</groupId> <artifactId>javafx-fxml</artifactId> <version>11</version> </dependency> </dependencies>
После этого вы заметите, что классы JavaFX теперь распознаются в редакторе.
Вы заметите, что Maven управляет необходимыми зависимостями для вас: он добавит javafx.base и javafx.graphics для javafx.controls, но самое главное, он добавит требуемый классификатор на основе вашей платформы. В моем случае, Mac.
Вот почему ваши jar файлы org.openjfx:javafx-controls:11
пусты, потому что есть три возможных классификатора (платформы Windows, Linux и Mac), которые содержат все классы и собственную реализацию.
Если вы все еще хотите пойти в репозиторий .m2 и взять оттуда зависимости вручную, убедитесь, что вы выбрали правильный (например, .m2/repository/org/openjfx/javafx-controls/11/javafx-controls-11-mac.jar
)
Замените стандартные плагины maven на здесь.
Запустите
mvn compile javafx:run
, и оно должно работать.
Аналогичное работает и для проектов Gradle, как подробно описано здесь здесь.
EDIT
Упомянутое руководство по началу работы содержит обновленную документацию и примеры проектов для IntelliJ:
Ответ №1
Проблема в том, что Java FX больше не является частью JDK 11. Следующее решение работает с использованием IntelliJ (еще не пробовал с NetBeans):
Добавьте глобальную библиотеку JavaFX в качестве зависимости:
Настройки → Структура проекта → Модуль. В модуле перейдите на вкладку «Зависимости» и нажмите значок «+» добавления → Библиотека → Java-> выберите JavaFX из списка и нажмите «Добавить выбранное», затем «Применить настройки».
Щелкните правой кнопкой мыши исходный файл (src) в вашем проекте JavaFX и создайте новый файл module-info.java. Внутри файла напишите следующий код:
module YourProjectName { requires javafx.fxml; requires javafx.controls; requires javafx.graphics; opens sample;}
Эти 2 шага решат все ваши проблемы с JavaFX, уверяю вас.
Ссылка: Там учебник You Tube, сделанный каналом Learn Programming, объяснит все детали выше всего за 5 минут. Я также рекомендую посмотреть его, чтобы решить вашу проблему: https://www.youtube.com/watch?v=WtOgoomDewo
Ответ №2
Ничто из вышеперечисленного не помогло мне. Я потратил слишком много времени на устранение других ошибок. Я обнаружил, что это самый простой и лучший способ.
Это работает для получения JavaFx на JDK 11, 12 & на OpenJdk12 тоже!
- Видео показывает загрузку JavaFx Sdk
- Как установить его в качестве глобальной библиотеки
- Установите module-info.java (я предпочитаю нижний)
module thisIsTheNameOfYourProject {
requires javafx.fxml;
requires javafx.controls;
requires javafx.graphics;
opens sample;
}
Все это заняло у меня всего 5 минут !!!
Ответ №3
Проверьте локальный.m2, была ли загружена банка или нет в местоположении
Ответ №4
Ответ №5
Ответ №6
Быстрая сводка, вы можете сделать:
Включите модули JavaFX через
--module-path
и--add-modules
, как в ответе Хосе.ИЛИ
Как только у вас есть библиотеки JavaFX, добавленные в ваш проект (вручную или через импорт maven/gradle), добавьте файл
module-info.java
, аналогичный указанному в этом ответе. (Обратите внимание, что это решение делает ваше приложение модульным, поэтому, если вы используете другие библиотеки, вам также потребуется добавить операторы, чтобы их модули содержались в файлеmodule-info.java
).
Этот ответ является дополнением к ответу Хосе.
Ситуация такая:
- Вы используете последнюю версию Java, например, 13.
- У вас есть приложение JavaFX в качестве проекта Maven.
- В вашем проекте Maven у вас настроен плагин JavaFX и настроены зависимости JavaFX в соответствии с ответом Jose.
- Вы переходите к исходному коду вашего основного класса, который расширяет Application, вы щелкаете по нему правой кнопкой мыши и пытаетесь запустить его.
- Вы получаете
IllegalAccessError
с «безымянным модулем» при попытке запустить приложение.
Выдержка для трассировки стека, генерирующей IllegalAccessError
при попытке запустить приложение JavaFX из Intellij Idea:
Exception in Application start method
java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:464)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:363)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1051)
Caused by: java.lang.RuntimeException: Exception in Application start method
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:900)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
at java.base/java.lang.Thread.run(Thread.java:830)
Caused by: java.lang.IllegalAccessError: class com.sun.javafx.fxml.FXMLLoaderHelper (in unnamed module @0x45069d0e) cannot access class com.sun.javafx.util.Utils (in module javafx.graphics) because module javafx.graphics does not export com.sun.javafx.util to unnamed module @0x45069d0e
at com.sun.javafx.fxml.FXMLLoaderHelper.<clinit>(FXMLLoaderHelper.java:38)
at javafx.fxml.FXMLLoader.<clinit>(FXMLLoader.java:2056)
at org.jewelsea.demo.javafx.springboot.Main.start(Main.java:13)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
Exception running application org.jewelsea.demo.javafx.springboot.Main
Хорошо, теперь вы застряли и понятия не имеете, что происходит.
На самом деле произошло следующее:
- Maven успешно загрузил зависимости JavaFX для вашего приложения, поэтому вам не нужно отдельно загружать зависимости или устанавливать JavaFX SDK или дистрибутив модуля или что-то подобное.
- Idea успешно импортировала модули как зависимости в ваш проект, поэтому все компилируется нормально, все завершение кода и все работает нормально.
Так что, похоже, все должно быть в порядке. НО, когда вы запускаете свое приложение, код в модулях JavaFX дает сбой при попытке использовать отражение для создания экземпляров класса вашего приложения (при вызове запуска) и классов контроллера FXML (при загрузке FXML). Без некоторой помощи это использование отражения может в некоторых случаях потерпеть неудачу, порождая неясность IllegalAccessError
. Это происходит из-за функции безопасности системы модулей Java, которая не позволяет коду из других модулей использовать отражение в ваших классах, если вы явно не разрешаете это (а для запуска приложений JavaFX и FXMLLoader оба требуют отражения в их текущей реализации, чтобы они могли функционировать правильно).
Вот где некоторые другие ответы на этот вопрос, которые ссылаются на module-info.java
, входят в картину.
Итак, давайте пройдем ускоренный курс по модулям Java:
Ключевая часть такова:
4.9. Opens
Если нам нужно разрешить отражение частных типов, но мы не хотим, чтобы все нашего кода, мы можем использовать директиву opens, чтобы пакеты.
Но помните, это откроет пакет для всего мира, поэтому убедитесь, что это то, что вы хотите:
module my.module { opens com.my.package; }
Поэтому, возможно, вы не хотите открывать свою посылку для всего мира, тогда вы можете сделать следующее:
4.10. Opens … To
Хорошо, иногда рефлексия великолепна, но мы по-прежнему хотим обеспечить максимальную безопасность, которую мы можем получить от инкапсуляции. Мы можем выборочно открывать наши пакеты для предварительно утвержденного списка модулей, в этом случае, используя директиву opens… to:
module my.module { открывает com.my.package для moduleOne, moduleTwo и т.д.; }
Итак, вы заканчиваете тем, что создали класс src/main/java/module-info.java, который выглядит следующим образом:
module org.jewelsea.demo.javafx.springboot {
requires javafx.fxml;
requires javafx.controls;
requires javafx.graphics;
opens org.jewelsea.demo.javafx.springboot to javafx.graphics,javafx.fxml;
}
Где, org.jewelsea.demo.javafx.springboot
— это имя пакета, который содержит класс приложения JavaFX и классы контроллера JavaFX (замените его соответствующим именем пакета для вашего приложения). Это сообщает среде выполнения Java, что классы в javafx.graphics
и javafx.fxml
могут вызывать отражение в классах в вашем пакете org.jewelsea.demo.javafx.springboot
. Как только это будет сделано, приложение скомпилировано и перезапущено, все будет работать нормально, и IllegalAccessError
, сгенерированный JavaFX, использует отражение больше не будет.
Но что, если вы не хотите создавать файл module-info.java
Если вместо непосредственного запуска класса приложения вместо кнопки «Выполнить» на верхней панели инструментов среды IDE, вы вместо этого:
- Пошел к окну Maven на боковой панели IDE.
- Выберите цель для плагина javafx maven
javafx.run
. - Щелкните по нему правой кнопкой мыши и выберите либо
Run Maven Build
, либоDebug...
.
Тогда приложение будет работать без файла module-info.java
. Я полагаю, это потому, что плагин maven достаточно умен, чтобы динамически включать в себя какие-то настройки, которые позволяют отражать приложение в классах JavaFX даже без файла module-info.java
, хотя я не знаю, как это сделать.
Чтобы передать эту настройку кнопке «Выполнить» на верхней панели инструментов, щелкните правой кнопкой мыши цель javafx.run
Maven и выберите для цели параметр Create Run/Debug Configuration
. Затем вы можете просто выбрать Run на верхней панели инструментов для выполнения цели Maven.
Плагин Javadoc для Apache Maven
— Использование ресурсов Javadoc
Использование ресурсов Javadoc
Параметр
Вот типичный набор файлов ресурсов, используемых плагином Maven Javadoc:
ваш проект | - src | - главная | - java | | - org | | - apache | | - myapp | `- Приложение.Ява | `- package-info.java | - javadoc `- overview.html | -ресурсы | - org | - apache | - myapp `- package.html | - doc-файлы `- app.png
Обзор Комментарий Файл: overview.html
Содержит комментарии о наборе пакетов. overview.html — это общая документация, которая применяется ко всему приложению или набору пакетов.
Для получения дополнительной информации см. Javadoc — Генератор документации Java API, Обзорный файл комментариев.
Вот пример файла overview.html , расположенного в $ {basedir} /src/main/javadoc/overview.html :
<ГОЛОВА>Обзор API <ТЕЛО> Краткий обзор API.