Domanda

Ryan Delucchi ha chiesto qui nel commento n. 3 a Risposta di Tom Hawtin :

  

perché Class.newInstance () " evil " ;?

questo in risposta all'esempio di codice:

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

quindi, perché è il male?

È stato utile?

Soluzione

La documentazione dell'API Java spiega perché ( http://java.sun.com/javase/6/docs/api/java/lang/Class.html#newInstance () ):

  

Si noti che questo metodo propaga qualsiasi eccezione generata dal costruttore nullary, inclusa un'eccezione controllata. L'uso di questo metodo ignora efficacemente il controllo delle eccezioni in fase di compilazione che verrebbe altrimenti eseguito dal compilatore. Il metodo Constructor.newInstance evita questo problema racchiudendo qualsiasi eccezione generata dal costruttore in un InvocationTargetException (controllato).

In altre parole, può sconfiggere il sistema di eccezioni verificato.

Altri suggerimenti

Un motivo in più:

Gli IDE moderni ti consentono di trovare gli utilizzi delle classi - aiuta durante il refactoring, se tu e il tuo IDE sapete quale codice sta usando la classe che intendete cambiare.

Quando non si fa un uso esplicito del costruttore, ma si utilizza Class.newInstance (), si rischia di non trovarlo durante il refactoring e questo problema non si manifesterà durante la compilazione.

Non so perché nessuno abbia fornito una semplice spiegazione di esempio a questo, rispetto ad esempio a Costruttore :: newInstance , poiché infine Class :: newInstance è stato deprecato dal java-9.

Supponi di avere questa classe molto semplice (non importa che sia rotta):

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

E provi a crearne un'istanza tramite reflection. Prima Class :: newInstance :

    Class<Foo> clazz = ...

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

Chiamando questo si genererà un IOException - il problema è che il tuo codice non lo gestisce, né gestisce 1 gestisce 2 lo prenderà.

Al contrario quando lo si fa tramite un costruttore :

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

verrà chiamato quell'handle 3, quindi lo gestirai.

In effetti, Class :: newInstance ignora la gestione delle eccezioni, cosa che davvero non vuoi.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top