Исключение ClassNotFound в предложении catch

public class dummy {
    public static void main(String[] args) { System.out.println("hello world"); }

    public void init() {
        //"dummy2" class defined in a different jar
        dummy2 d = new dummy2(); 
        try { d.run(); } 
        //"dummyexception" class defined in a different jar
        catch (dummyexception e) { e.printStackTrace(); }
        catch (Exception e) { e.printStackTrace(); }
    }

    public void init2() {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                //"dummy2" class defined in a different jar
                dummy2 d = new dummy2(); 
                try { d.run(); } 
                //"dummyexception" class defined in a different jar
                catch (dummyexception e) { e.printStackTrace(); } 
                catch (Exception e) { e.printStackTrace(); }        
            }
        };
    }
}

Теперь перед запуском я удалил зависимую банку из пути к классам. Я получил 'ClassNotFoundException"для класса"dummyexceptionссылаться в методе init() а не для использования в методе init2(), Интересно нетClassNotFoundException"для класса"dummy2ссылаться в методе init(),

3 ответа

Теперь перед запуском я удалил зависимую банку из пути к классам. Я получаю ClassNotFoundException для класса "dummyexception", на который ссылается метод init(), а не для использования в методе init2().

Учебный класс dummy2 будет загружаться только тогда, когда будет запущен метод init. Несмотря на dummyexcetion является параметром catch, поэтому JVM обрабатывает этот класс как метод java. Полное имя для dummyexception класс помещается в файл jvm *.class constant_pool и JVM проверяет доступность класса перед dummy был загружен.

Давайте рассмотрим пример:

public class Dummy {

    public void init(){
        DummyExternal dummy = new DummyExternal();
        try {
            dummy.run();
        } catch(DummyException e) {
        } catch(Exception e){ }
    }

    public void init2(){
        new Runnable() {            
            @Override
            public void run() {
                DummyExternal dummy = new DummyExternal();
                try {
                    dummy.run();
                } catch(DummyException e) {
                    e.printStackTrace();
                } catch(Exception e){}
            }
        }.run();
    }

    public static void main(String[] args){
        System.out.println("hello world");
    }

}



public class DummyException extends RuntimeException {

    private static final long serialVersionUID = 2049347223914508696L;

    static {
        System.out.println("DummyException");
    }

}


public class DummyExternal implements Runnable {

    static {
        System.out.println("DummyExternal");
    }

    @Override
    public void run() {
        System.out.println("DummyExternal");
    }

}

В результате мы будем иметь:

-rw-r -r-- 1 такой персонал 756B 19 мая 08:26 Пустышка $ 1.класс

-rw-r -r-- 1 такой персонал 956B 19 мая 08:26 Dummy.class

-rw-r -r-- 1 такой персонал 545B 19 мая 08:26 DummyException.class

-rw-r -r-- 1 такой персонал 569B 19 мая 08:26 DummyExternal.class

команда java Dummy Распечатать hello world, Так нет DummyExternal или же DummyException класс был загружен.

Удалить DummyExternal файл класса: rm DummyExternal.class, Результат java Dummy не меняй.

Давайте удалим DummyException файл класса: rm DummyException.class,

И после исполнения java Dummy мы получаем интересную трассировку стека.

Exception in thread "main" java.lang.NoClassDefFoundError: DummyException
    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2442)
    at java.lang.Class.getMethod0(Class.java:2685)
    at java.lang.Class.getMethod(Class.java:1620)
    at sun.launcher.LauncherHelper.getMainMethod(LauncherHelper.java:494)
    at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:486)
Caused by: java.lang.ClassNotFoundException: DummyException
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
    ... 6 more

Такое поведение обусловлено механизмом обработки исключений. Если class является параметром catch, генерируют обработчики исключений, которые должны быть разрешены при обработке исключения. Механизм обработки исключений аналогичен вызову метода и разрешению ClassLoader DummyException из постоянного пула до загрузки класса.

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

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

Мой взгляд на это:

По моему мнению, вы не должны получать никаких ошибок, потому что init() а также init2(), которые используют зависимые банки, не вызываются никакими функциями.

Какова связь между не вызываемыми функциями и генерацией ошибок?

Когда вы компилируете свои классы, JVM создает файлы классов. В этих файлах классов JVM создает symbolic string references к вызову методов и классов путем поиска классов в classpath, Если он не находит ссылочные классы, вы получите ошибки во время компиляции, и ваши классы не будут компилироваться. Если он найдет его, значит, ваша компиляция прошла успешно, а затем JVM добавит symbolic string references внутри файла класса. Там нет актуального pointer to methods and classes на данный момент.

Теперь, когда вы запускаете вашу программу, ваши вызовы методов находятся в виде тех symbolic string references в файле класса. На данный момент эти symbolic references превращаются в actual pointers to classes and methods, На данный момент ваш class loader будет искать эти зависимые классы only if ссылочные методы вызываются из некоторого метода. Если он не находит зависимые классы в пути к классам, генерируется ошибка. Замечания: class loader не будет искать зависимые классы, если методы не вызываются. Symbolic instructions будет проигнорировано, и ошибка не будет сгенерирована.

Что происходит в вашем случае?

Я не вижу твоего init() а также init2() быть вызванным кем-либо. Что значит class loader не нужно искать dependent jars а также create pointer to these methods, Это означает, что вы не должны получать никаких ошибок Unless что-то вызывает эти методы.

Другие вопросы по тегам