Хотя мой класс был загружен, Class.forName выбрасывает ClassNotFoundException

Код выглядит следующим образом

он загружает все классы в файл jar, который я поместил в свой домашний каталог.

import java.io.File;
import java.util.jar.JarFile;
import java.util.jar.JarEntry;
import java.net.URLClassLoader;
import java.net.URL;
import java.util.Enumeration;
import java.lang.ClassLoader;
public class Plugin extends ClassLoader {
public static void main(String[] args) throws Exception {

    File file = new File(System.getProperty("user.home") + "/HelloWorld.jar");

    URLClassLoader clazzLoader = URLClassLoader.newInstance(new URL[]{file.toURI().toURL()});

    JarFile jarFile = new JarFile(file);
    Enumeration<JarEntry> entries = jarFile.entries();

    while (entries.hasMoreElements()) {
        JarEntry element = entries.nextElement();
        if (element.getName().endsWith(".class")) {
            try {
                Class c = clazzLoader.loadClass(element.getName().replaceAll(".class", "").replaceAll("/", "."));
                c.newInstance(); // this proves that class is loaded
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    Class cls = Class.forName("HelloWorld");
    cls.newInstance();
    Plugin p = new Plugin();
    p.checkIfLoaded();

}

public void checkIfLoaded() {
System.out.println("coming in");
if (findLoadedClass("HelloWorld") != null){
        System.out.println("Yepee, HelloWorld class is loaded !");
}
}

}

Мой HelloWorld такой же, как в https://github.com/HarishAtGitHub/doc/blob/master/makeExecutableJar/HelloWorld.java

и банку можно получить с помощью инструкций в моей учетной записи github, упомянутых выше.

c.newInstance() работает.

Как я подтвердил?

статический блок был выполнен ...

но Class.forName("HelloWorld") бросает ClassNotFoundException

также findLoadedClass("HelloWorld") имеет значение null ..

Я не могу понять, почему это странное поведение?

Пожалуйста, направьте ...


person Harish Kayarohanam    schedule 13.02.2014    source источник
comment
Класс HelloWorld находится в пакете по умолчанию ??   -  person Kick    schedule 13.02.2014
comment
нет .. Это как раз на том же уровне, что и папка META-INF ....   -  person Harish Kayarohanam    schedule 13.02.2014


Ответы (2)


Это проблема загрузчика классов.

Согласно Документация Javadocs к Class.forName, вы ищете класс, используя загрузчик классов текущего класса. В качестве основного класса это будет загрузчик классов JVM (и будет более или менее просто включать стандартную библиотеку плюс все, что вы указали в качестве аргумента командной строки -cp). Он не будет делегировать загрузчику классов, который вы создали как локальную переменную, и поэтому не будет возвращать классы, которые этот загрузчик классов может найти.

Если вы явно укажете загрузчик классов и вызовете

Class.forName("HelloWorld", true, clazzloader)

тогда вместо этого будет произведен поиск только что созданного загрузчика классов и будет найден ваш класс.

person Andrzej Doyle    schedule 13.02.2014
comment
я. так что нигде нельзя проверить, был ли загружен мой класс? должен ли мой clazzLoader всегда передаваться? хранится ли загруженная информация о классе в общем месте? - person Harish Kayarohanam; 13.02.2014
comment
Самый простой способ справиться с этой конкретной ситуацией - загрузить ваши классы загрузчиком классов начальной загрузки (то есть основным). Если вы передадите HelloWorld.jar в качестве -cp аргумента для вашего вызова Java, классы в нем будут автоматически загружены основным загрузчиком классов, вам не нужно будет больше ничего делать. (Или, если само приложение является JAR, вы можете установить свойство Class-Path его манифеста.) - person Andrzej Doyle; 13.02.2014
comment
В противном случае, если вам нужно создать загрузчик классов во время выполнения (по какой-либо причине), вы, вероятно, захотите установить его как Загрузчик классов контекста потока для относительно простого способа передать его. Вам, вероятно, по-прежнему потребуется некоторая ручная работа, чтобы получить из него загрузчик классов, поскольку по умолчанию для поиска других классов используется собственный загрузчик классов. Если вам нужно другое поведение, обычно вам нужно явно указать загрузчик классов. - person Andrzej Doyle; 13.02.2014

Поскольку Class.forName (String) использует currentClassLoader, и вы загрузили класс в другой ClassLoader.

Согласно javadoc, вызов Class.forName (String) эквивалентен:

Class.forName(className, true, currentLoader) 
person rdllopes    schedule 13.02.2014