Вопрос

Райан Делуччи спросил здесь в комментарии № 3 к Ответ Тома Хотина :

  

Почему Class.newInstance () "злой"?

это в ответ на пример кода:

// Avoid Class.newInstance, for it is evil.
Constructor<? extends Runnable> ctor = runClass.getConstructor();
Runnable doRun = ctor.newInstance();

Итак, почему это зло?

Это было полезно?

Решение

Документация по Java API объясняет почему ( http://java.sun.com/javase/6/docs/api/java/lang/Class.html#newInstance () ):

  

Обратите внимание, что этот метод распространяет любое исключение, выбрасываемое нулевым конструктором, включая проверенное исключение. Использование этого метода эффективно обходит проверку исключений во время компиляции, которая в противном случае выполнялась бы компилятором. Метод Constructor.newInstance позволяет избежать этой проблемы, поместив любое исключение, сгенерированное конструктором, в (проверенный) InvocationTargetException .

Другими словами, он может победить систему проверенных исключений.

Другие советы

Еще одна причина:

Современные IDE позволяют вам найти использование классов - это помогает во время рефакторинга, если вы и ваша IDE знаете, какой код использует класс, который вы планируете изменить.

Если вы не используете явное использование конструктора, а используете Class.newInstance (), вы рискуете не обнаружить его при рефакторинге, и эта проблема не проявится при компиляции.

Я не знаю, почему никто не предоставил простое объяснение, основанное на этом примере, по сравнению, например, с Constructor :: newInstance , поскольку класс finally :: newInstance устарела с java-9.

Предположим, у вас есть очень простой класс (не имеет значения, что он сломан):

static class Foo {
    public Foo() throws IOException {
        throw new IOException();
    }
}

И вы пытаетесь создать его экземпляр с помощью отражения. Первый Class :: newInstance :

    Class<Foo> clazz = ...

    try {
        clazz.newInstance();
    } catch (InstantiationException e) {
        // handle 1
    } catch (IllegalAccessException e) {
        // handle 2
    }

Вызов этого приведет к созданию IOException - проблема в том, что ваш код не обрабатывает его, ни handle 1 , ни handle 2 поймаю это.

В отличие от этого при использовании Конструктора :

    Constructor<Foo> constructor = null;
    try {
        constructor = clazz.getConstructor();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    }

    try {
        Foo foo = constructor.newInstance();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        System.out.println("handle 3 called");
        e.printStackTrace();
    }

этот дескриптор 3 будет вызван, поэтому вы будете обрабатывать его.

По сути, Class :: newInstance обходит обработку исключений - что вам действительно не нужно.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top