NoClassDefFoundError when adding classes to the classpath at runtime when I used abstract or interface in Main class

孤人 提交于 2019-12-11 04:44:49

问题


I know Java loads Classes in first Access (creating new Instance, calling static method or static field), but in this simple example I try to execute a jar file that uses some classes which there aren't in my ClassPath at run time. I expect (because of loading classes in first access) print my messages in static block and main method before an exception occurred. but I got "Exception in thread "main" java.lang.NoClassDefFoundError: com/example/DateAbstract" and nothing printed. This occurred when I used an abstract class or interface in main class which that classes or interfaces are in another jar file.

public class Driver {
static { System.out.println("I am first.[static block]"); }
public static void main(String[] args) {
    System.out.println("I am first.[ main method]");
    DateAbstract date = new CustomDate();
    System.out.println(date.sayDate());
}

in my another jar :

public class CustomDate extends DateAbstract {
@Override
public String sayDate() {
    return new Date().toString();
}
public abstract class DateAbstract {
public abstract String sayDate();

}

when I use this code for add my classes to classpath at runtime. nothing changed. I got execption before execute static block.

public class Driver {
static {
    System.out.println("I am first.[static block]");
    try {
        URL url = new File("lib/DateApi.jar").toURI().toURL();
        URLClassLoader urlClassLoader = (URLClassLoader) URLClassLoader.getSystemClassLoader();
        Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
        method.setAccessible(true);
        method.invoke(urlClassLoader,url);
    } catch (Exception e) {
        e.printStackTrace();
    }

}
public static void main(String[] args) {
    System.out.println("I am first.[ main method]");
    DateAbstract date = new CustomDate();
    System.out.println(date.sayDate());
}

}

Questions : why is this happening and how to solve it ?


回答1:


It’s not correct to say that in Java classes are loaded on their first access. You are confusing this with the initialization of a class, which implies executing the Java code of static initializer blocks and field initializers. The loading and verification might happen at an earlier time; the specification provides some freedom to the JVMs in this regard.

The key point here is that your main method instantiates an object of type CustomDate, stores it into a variable of the compile-time type DateAbstract and then tries to invoke sayDate() on that variable. This combination of instantiating CustomDate and invoking DateAbstract.sayDate() on it requires the verification of its correctness, i.e. whether CustomDate is a subtype DateAbstract. So the loading of these two classes will already happen at verification time.

You can easily check that this is the cause. If you change the type of the local variable date to CustomDate, the instantiated type and the receiver type of the method invocation are the same, so the correctness can be proven without loading the type, so it will be indeed deferred to the actual attempt to instantiate CustomDate, hence the messages will be printed.

Still, the loading time is an implementation-specific detail. A different JVM could load the referenced classes eagerly, even if they are not required for verification. The only safe way to ensure a deferred loading, is to use dynamic loading, e.g. Class.forName(String). Note that within the class detached this way, all types might be again referenced ordinarily. So if you do the dynamic loading once after the class path has been adjusted, there is not much impact on how you have to write the code nor its performance. Of course, having the code adjusting the class path and the code depending on it within the same class won’t work reliably.



来源:https://stackoverflow.com/questions/38673384/noclassdeffounderror-when-adding-classes-to-the-classpath-at-runtime-when-i-used

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!