99 votes

Pourquoi Class.newInstance() est-il "mauvais" ?

Ryan Delucchi a demandé aquí dans le commentaire n° 3 à Tom Hawtin La réponse de la Commission :

pourquoi Class.newInstance() est-il "mauvais" ?

ceci en réponse à l'exemple de code :

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

alors, pourquoi c'est le Mal ?

11 votes

En fait, en voyant les réponses à cette question, on pourrait dire cela à propos d'une variété d'utilisations de la réflexion ... pas seulement de Class.newInstance(). Il s'agit donc d'une observation générale selon laquelle "la réflexion fait échouer la vérification au moment de la compilation" ... ce qui est souvent le but de la réflexion.

25 votes

Les jeunes d'aujourd'hui, Oh oui, ils jettent autour du mot "EVIL" mais ils n'ont jamais vu un programme COBOL ou FORTRAN ! Si vous voulez du "MAUVAIS", jetez un coup d'oeil à un programme FORTRAN vieux de 20 ans qui a été passé d'un projet à l'autre par des bricoleurs ayant une formation en simulation et aucune influence CS ! Voilà qui est "MALIN" !

0 votes

83voto

Chris Jester-Young Points 102876

La documentation de l'API Java explique pourquoi ( [http://java.sun.com/javase/6/docs/api/java/lang/Class.html#newInstance()](http://java.sun.com/javase/6/docs/api/java/lang/Class.html#newInstance()) ):

Notez que cette méthode propage toute exception lancée par le constructeur nullaire, y compris une exception vérifiée. L'utilisation de cette méthode permet de contourner la vérification des exceptions au moment de la compilation, qui serait autrement effectuée par le compilateur. L'adresse Constructor.newInstance évite ce problème en enveloppant toute exception levée par le constructeur dans une exception (vérifiée) InvocationTargetException .

En d'autres termes, il peut déjouer le système des exceptions contrôlées.

12 votes

C'est la nature même de la réflexion en général ... pas du tout spécifique à Constructor.newInstance().

29 votes

@Ryan : Ce n'est pas vrai ; toutes les autres méthodes d'invocation basées sur la réflexion lèvent une exception vérifiée appelée InvocationTargetException qui englobe tous les éléments à rejeter lancés par la méthode invoquée. Class.newInstance ne le fera pas - il lancera directement l'exception vérifiée. L'inconvénient est que javac ne vous laissera pas non plus essayer d'attraper ces exceptions, parce que Class.newInstance n'est pas déclaré pour les lancer.

23voto

alexei.vidmich Points 320

Une raison de plus :

Les IDE modernes vous permettent de trouver les utilisations des classes - cela aide lors du remaniement, si vous et votre IDE savez quel code utilise la classe que vous prévoyez de modifier.

Lorsque vous ne faites pas un usage explicite du constructeur, mais que vous utilisez Class.newInstance() à la place, vous risquez de ne pas trouver cet usage lors du refactoring et ce problème ne se manifestera pas lors de la compilation.

21 votes

C'est aussi un problème général lié à l'utilisation de la réflexion.

15voto

Eugene Points 6271

Je ne sais pas pourquoi personne n'a fourni d'explication simple basée sur un exemple, par rapport à la situation suivante Constructor::newInstance par exemple, puisque enfin Class::newInstance est déprécié depuis java-9.

Supposons que vous ayez cette classe très simple (peu importe qu'elle soit cassée) :

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

Et vous essayez d'en créer une instance par réflexion. D'abord Class::newInstance :

    Class<Foo> clazz = ...

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

L'appel de cette fonction entraînera un IOException Le problème, c'est que votre code ne le gère pas. handle 1 ni handle 2 l'attrapera.

En revanche, lorsque vous le faites via un 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();
    }

que la poignée 3 sera appelée, donc vous la traiterez.

Efficacement, Class::newInstance contourne la gestion des exceptions - ce que vous ne voulez vraiment pas.

0voto

musthak Points 1

Nous ne pouvons pas utiliser l'opérateur new pour créer un objet de classe java qui vient à l'application de façon dynamique au moment de l'exécution, pour cela nous devons utiliser newInstance() de java.lang.Class .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X