Почему Class.newInstance () "злой"? - PullRequest
89 голосов
/ 12 октября 2008

Райан Делукки спросил здесь в комментарии № 3 к Tom Hawtin ответ:

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

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

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

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

Ответы [ 3 ]

81 голосов
/ 12 октября 2008

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

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

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

19 голосов
/ 13 октября 2008

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

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

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

7 голосов
/ 26 октября 2018

Я не знаю, почему никто не предоставил простое объяснение, основанное на примере, по сравнению с, например, Constructor::newInstance, так как окончательно Class::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:

    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 обходит обработку исключений - что вам действительно не нужно.

...