Java загружает классы через ClassLoaders. Когда вы запускаете JVM, вы должны сообщить JVM «путь к классам», то есть список папок или jar-файлов, в которых находятся классы. JVM создаст ClassLoader (обычно подкласс URLClassLoader) и предоставит этому ClassLoader список папок и jar-файлов, чтобы загрузчик классов мог загрузить класс.
В вашем приложении, когда вы компилируете исходный файл Java, оно генерирует файл класса, который сохраняется где-то. Вероятно, в eclipse папка, в которой сохранен файл класса, является папкой, включенной в путь к классам, так что JVM сможет найти класс.
Когда вы экспортируете проект в работающий JAR-файл, возможно, JVM будет запущен, имея только этот JAR-файл в своем пути к классам, чтобы он нигде не искал скомпилированный класс.
У вас есть несколько способов исправить это. В порядке возрастания сложности:
- Запустите jar-файл не как исполняемый jar-файл, а с помощью .bat / .sh или любого другого java-бегуна, который позволяет настраивать classpath, добавлять определенную папку в classpath, компилировать исходные файлы java в эту папку. .
- Когда вы компилируете файл Java, создайте папку и создайте новый экземпляр URLClassLoader, указывающий на эту папку. Скомпилируйте файл Java в эту папку. Затем используйте этот URLCLassLoader для загрузки скомпилированного класса.
- Скомпилируйте исходный код Java в ОЗУ, например, в байтовый массив, и реализуйте специальный загрузчик классов, который будет возвращать этот байтовый массив вместо загрузки с диска.
Решение 1 очень простое, но имеет свои недостатки: не будет возможности перезагрузить скомпилированный Java-файл, если не будет снова запущена вся программа (как только класс загружен в загрузчик классов, он не может быть загружен снова, за исключением использования агенты, которые выходят за рамки этого вопроса), она требует, чтобы программа записывала на диск, что означает разрешения и т. д.
Решение 2 и его эволюция, которая заключается только в оперативной памяти, намного более элегантны, но гораздо сложнее: загрузка одного класса из загрузчика классов отличается от того, который используется остальной частью всего вашего приложения, сложно, вы можете получить странные исключения класса (например, ClassCastExceptions, ClassNotFoundException и т. д.) из-за несоответствия между загрузчиками классов.