Как я могу загрузить класс, который не находится в том же архиве jar, что и текущий класс? - PullRequest
2 голосов
/ 31 августа 2011

Положение:

Я делаю симулятор для построения временной сложности алгоритмов. Студенты могут добавить загрузить свой собственный файл .java для его запуска. Моя программа компилирует (с помощью 'JavaCompiler') файл .java. Затем он пытается загрузить файл .class:

loadedClass = loadClass("customAlgorithms."+this.getClassName()+"");

При запуске моей программы в Eclipse все работает нормально, и студенты могут безупречно ее использовать.

Проблема:

Но затем я экспортирую свой проект в исполняемый файл JAR. Компиляция все еще работает, но загрузка класса завершается неудачно, потому что он ищет его внутри файла jar.

Мне было интересно, почему я не мог просто сделать это: (изменить. С /)

loadedClass = loadClass("customAlgorithms/"+this.getClassName()+"");

Какие варианты возможны? Вот что я могу придумать:

  • добавление скомпилированного файла .class в текущий запущенный файл .jar. Это может даже работать?

    Я знаю, что можно редактировать jar-архив. Но может ли это работать во время работы и без перезапуска программы?

  • другой способ использовать loadClass ()? Чтобы я мог загрузить файл класса, который не включен в мой файл jar

Есть ли другие идеи?

Ответы [ 3 ]

3 голосов
/ 31 августа 2011

Java загружает классы через ClassLoaders. Когда вы запускаете JVM, вы должны сообщить JVM «путь к классам», то есть список папок или jar-файлов, в которых находятся классы. JVM создаст ClassLoader (обычно подкласс URLClassLoader) и предоставит этому ClassLoader список папок и jar-файлов, чтобы загрузчик классов мог загрузить класс.

В вашем приложении, когда вы компилируете исходный файл Java, оно генерирует файл класса, который сохраняется где-то. Вероятно, в eclipse папка, в которой сохранен файл класса, является папкой, включенной в путь к классам, так что JVM сможет найти класс.

Когда вы экспортируете проект в работающий JAR-файл, возможно, JVM будет запущен, имея только этот JAR-файл в своем пути к классам, чтобы он нигде не искал скомпилированный класс.

У вас есть несколько способов исправить это. В порядке возрастания сложности:

  1. Запустите jar-файл не как исполняемый jar-файл, а с помощью .bat / .sh или любого другого java-бегуна, который позволяет настраивать classpath, добавлять определенную папку в classpath, компилировать исходные файлы java в эту папку. .
  2. Когда вы компилируете файл Java, создайте папку и создайте новый экземпляр URLClassLoader, указывающий на эту папку. Скомпилируйте файл Java в эту папку. Затем используйте этот URLCLassLoader для загрузки скомпилированного класса.
  3. Скомпилируйте исходный код Java в ОЗУ, например, в байтовый массив, и реализуйте специальный загрузчик классов, который будет возвращать этот байтовый массив вместо загрузки с диска.

Решение 1 очень простое, но имеет свои недостатки: не будет возможности перезагрузить скомпилированный Java-файл, если не будет снова запущена вся программа (как только класс загружен в загрузчик классов, он не может быть загружен снова, за исключением использования агенты, которые выходят за рамки этого вопроса), она требует, чтобы программа записывала на диск, что означает разрешения и т. д.

Решение 2 и его эволюция, которая заключается только в оперативной памяти, намного более элегантны, но гораздо сложнее: загрузка одного класса из загрузчика классов отличается от того, который используется остальной частью всего вашего приложения, сложно, вы можете получить странные исключения класса (например, ClassCastExceptions, ClassNotFoundException и т. д.) из-за несоответствия между загрузчиками классов.

1 голос
/ 31 августа 2011

Вам нужно будет создать другой загрузчик классов, например URLClassLoader, и загрузить из него класс.

1 голос
/ 31 августа 2011

Вы можете использовать ClassLoader метод defineClass . Он защищен, но это не должно быть проблемой.

Если проблема в том, что метод защищен, вероятно, где-то в Интернете вы можете определить пользовательский подкласс с этой свободно доступной функциональностью.

...