Райан Делукки спросил здесь в комментарии №3 к ответу Том Хотин:
why is Class.newInstance() "evil"?
это в ответ на образец кода:
// Avoid Class.newInstance, for it is evil.
Constructor<? extends Runnable> ctor = runClass.getConstructor();
Runnable doRun = ctor.newInstance();
так почему это зло?
Дети в наши дни, о да, они используют слово «ЗЛО», но они никогда даже не ВИДИЛИ программу на КОБОЛ или ФОРТРАН! Вы хотите, чтобы "EVIL" взглянул на программу FORTRAN 20-летней давности, которая передавалась от проекта к проекту мастером с опытом моделирования и никаким влиянием CS! Теперь это "ЗЛО!"
См. Также stackoverflow.com/q/36272566/3888450




Документация по Java API объясняет, почему (http://java.sun.com/javase/6/docs/api/java/lang/Class.html#newInstance ()):
Note that this method propagates any exception thrown by the nullary constructor, including a checked exception. Use of this method effectively bypasses the compile-time exception checking that would otherwise be performed by the compiler. The
Constructor.newInstancemethod avoids this problem by wrapping any exception thrown by the constructor in a (checked)InvocationTargetException.
Другими словами, он может обойти проверенную систему исключений.
Это сама природа отражения в целом ... совершенно не специфична для Constructor.newInstance ().
@ Райан: Это неправда; все другие основанные на отражении методы вызова генерируют проверенное исключение с именем InvocationTargetException, которое обертывает любой бросаемый объект, выданный вызванным методом. Class.newInstance не будет этого делать - он вызовет проверенное исключение напрямую. Обратной стороной является то, что javac также не позволит вам попытаться перехватить эти исключения, потому что Class.newInstance не объявлен для их выдачи.
Еще одна причина:
Современные IDE позволяют находить использование классов - это помогает во время рефакторинга, если вы и ваша IDE знаете, какой код использует класс, который вы планируете изменить.
Если вы не используете конструктор явно, а вместо этого используете Class.newInstance (), вы рискуете не обнаружить такое использование во время рефакторинга, и эта проблема не проявится при компиляции.
Также общая проблема с использованием отражения.
Я не знаю, почему никто не предоставил простое объяснение на основе примеров по сравнению, например, с 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 обходит обработку исключений, чего вы на самом деле не хотите.
Фактически, видя ответы на этот вопрос: можно сказать это о различных применениях отражения ... не только о Class.newInstance (). Так что это действительно общее наблюдение, что «отражение побеждает проверку во время компиляции» ... что часто является точкой отражения.