it-swarm.com.de

Warum ist Class.newInstance () "böse"?

Ryan Delucchi fragte hier in Kommentar # 3 zu Tom Hawtin s Antwort:

warum ist Class.newInstance () "böse"?

dies als Antwort auf das Codebeispiel:

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

also, warum ist es böse?

90
Amir Arad

In der Java API-Dokumentation wird erklärt, warum ( http://Java.Sun.com/javase/6/docs/api/Java/lang/Class.html#newInstance () ):

Beachten Sie, dass diese Methode alle vom Nullary-Konstruktor ausgelösten Ausnahmen weitergibt, einschließlich einer aktivierten Ausnahme. Die Verwendung dieser Methode umgeht effektiv die Ausnahmebedingungsprüfung zur Kompilierungszeit, die sonst vom Compiler ausgeführt würde. Das Constructor.newInstance-Methode umgeht dieses Problem, indem jede vom Konstruktor ausgelöste Ausnahme in ein (angehaktes) InvocationTargetException eingeschlossen wird.

Mit anderen Worten, es kann das geprüfte Ausnahmesystem besiegen.

81

Ein Grund mehr:

Moderne IDEs ermöglichen es Ihnen, Klassennutzungen zu finden - es hilft beim Refactoring, wenn Sie und Ihre IDE wissen, welcher Code Klasse verwendet, die Sie ändern möchten.

Wenn Sie den Konstruktor nicht explizit verwenden, sondern stattdessen Class.newInstance () verwenden, besteht das Risiko, dass Sie diese Verwendung beim Refactoring nicht finden, und dieses Problem tritt beim Kompilieren nicht auf.

19
alexei.vidmich

Ich weiß nicht, warum im Vergleich zu Constructor::newInstance zum Beispiel seit endlichClass::newInstance ist seit Java-9 veraltet.

Angenommen, Sie haben diese sehr einfache Klasse (spielt keine Rolle, dass sie kaputt ist):

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

Und Sie versuchen, eine Instanz davon durch Reflektion zu erstellen. Zuerst Class::newInstance:

    Class<Foo> clazz = ...

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

Wenn Sie dies aufrufen, wird IOException ausgelöst. Das Problem besteht darin, dass Ihr Code weder handle 1 Noch handle 2 wird es fangen.

Im Gegensatz dazu, wenn Sie dies über ein Constructor tun:

    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();
    }

dieser Handle 3 wird aufgerufen, also werden Sie damit umgehen.

Tatsächlich Class::newInstance umgeht die Ausnahmebehandlung, die Sie wirklich nicht wollen.

7
Eugene