web-dev-qa-db-fra.com

Quelle est la différence entre "Class.forName ()" et "Class.forName (). NewInstance ()"?

Quelle est la différence entre Class.forName() et Class.forName().newInstance()?

Je ne comprends pas la différence significative (j'ai lu quelque chose à leur sujet!). Pourrais-tu m'aider s'il te plaît?

158
Johanna

Peut-être qu'un exemple montrant comment les deux méthodes sont utilisées vous aidera à mieux comprendre les choses. Alors, considérons la classe suivante:

package test;

public class Demo {

    public Demo() {
        System.out.println("Hi!");
    }

    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("test.Demo");
        Demo demo = (Demo) clazz.newInstance();
    }
}

Comme expliqué dans son document javadoc, l'appel Class.forName(String) renvoie l'objet Class associé à la classe ou à l'interface avec le nom de chaîne donné , c'est-à-dire qu'il renvoie test.Demo.class qui est affecté à la variable clazz de type Class.

Ensuite, l'appel clazz.newInstance() crée une nouvelle instance de la classe représentée par cet objet Class. La classe est instanciée comme si elle était une expression new avec une liste d’arguments vide. En d’autres termes, cela équivaut ici à un new Demo() et renvoie une nouvelle instance de Demo.

Et l’exécution de cette classe Demo affiche donc le résultat suivant:

Hi!

La grande différence avec le new traditionnel est que newInstance permet d’instancier une classe que vous ne connaissez pas jusqu’à l’exécution, ce qui rend votre code plus dynamique.

Un exemple typique est l'API JDBC qui charge, au moment de l'exécution, le pilote exact requis pour effectuer le travail. Les conteneurs EJB, les conteneurs Servlet sont d'autres bons exemples: ils utilisent le chargement dynamique au moment de l'exécution pour charger et créer des composants qu'ils ne connaissent pas avant le moment de l'exécution.

En fait, si vous voulez aller plus loin, jetez un coup d’œil à l’article de Ted Neward nderstanding Class.forName () que je paraphrasais dans le paragraphe précédent.

EDIT (répondant à une question de l'OP publiée en tant que commentaire): Le cas des pilotes JDBC est un peu spécial. Comme expliqué dans le chapitre DriverManager de Initiation à l'API JDBC :

(...) Une classe Driver est chargée, et donc automatiquement enregistrée avec DriverManager, de l'une des deux manières suivantes:

  1. en appelant la méthode Class.forName. Cela charge explicitement la classe de pilote. Comme elle ne dépend d'aucune configuration externe, cette méthode de chargement d'un pilote est recommandée pour utiliser le cadre DriverManager. Le code suivant charge la classe acme.db.Driver:

    Class.forName("acme.db.Driver");
    

    Si acme.db.Driver a été écrit de telle sorte que son chargement entraîne la création d'une instance et appelle également DriverManager.registerDriver avec cette instance comme paramètre (comme il se doit), il figure dans la liste des pilotes de DriverManager et est disponible pour la création d’une connexion.

  2. (...)

Dans ces deux cas, il appartient à la classe Driver nouvellement chargée de s'enregistrer en appelant DriverManager.registerDriver. Comme mentionné, cela devrait être fait automatiquement lorsque la classe est chargée.

Pour s’inscrire lors de l’initialisation, le pilote JDBC utilise généralement un bloc d’initialisation statique comme celui-ci:

package acme.db;

public class Driver {

    static {
        Java.sql.DriverManager.registerDriver(new Driver());
    }

    ...
}

L'appel de Class.forName("acme.db.Driver") provoque l'initialisation de la classe acme.db.Driver et donc l'exécution du bloc d'initialisation statique. Et Class.forName("acme.db.Driver") va en effet "créer" une instance, mais ce n'est qu'une conséquence de la manière dont le (bon) pilote JDBC est implémenté.

En remarque, je dirais que tout cela n’est plus nécessaire avec JDBC 4.0 (ajouté comme paquet par défaut depuis Java 7] et la nouvelle fonctionnalité de chargement automatique des pilotes JDBC 4.0. Voir Améliorations de JDBC 4.0 dans Java SE 6 .

238
Pascal Thivent

Class.forName () vous donne l'objet class, ce qui est utile pour la réflexion. Les méthodes de cet objet sont définies par Java et non par le programmeur qui écrit la classe. Ils sont les mêmes pour toutes les classes. L'appel de newInstance () sur une instance de cette classe (par exemple, appeler Class.forName("ExampleClass").newInstance() équivaut à appeler new ExampleClass()), sur lequel vous pouvez appeler les méthodes définies par la classe, accéder aux champs visibles, etc. .

35
Thomas Lötzer

Dans le monde JDBC, la pratique normale (selon l'API JDBC) consiste à utiliser Class#forName() pour charger un pilote JDBC. Le pilote JDBC doit notamment s’inscrire dans DriverManager dans un bloc statique:

package com.dbvendor.jdbc;

import Java.sql.Driver;
import Java.sql.DriverManager;

public class MyDriver implements Driver {

    static {
        DriverManager.registerDriver(new MyDriver());
    }

    public MyDriver() {
        //
    }

}

Invoquer Class#forName() exécutera tous les initialiseurs statiques . De cette façon, DriverManager peut trouver le pilote associé parmi les pilotes enregistrés par l'URL de connexion pendant getConnection() , qui ressemble à peu près à ce qui suit:

public static Connection getConnection(String url) throws SQLException {
    for (Driver driver : registeredDrivers) {
        if (driver.acceptsURL(url)) {
            return driver.connect(url);
        }
    }
    throw new SQLException("No suitable driver");
}

Mais il y avait aussi des pilotes JDBC bogués, commençant par le org.gjt.mm.mysql.Driver comme exemple bien connu, qui s’enregistre de manière incorrecte dans le constructeur au lieu d'un bloc statique:

package com.dbvendor.jdbc;

import Java.sql.Driver;
import Java.sql.DriverManager;

public class BadDriver implements Driver {

    public BadDriver() {
        DriverManager.registerDriver(this);
    }

}

La seule façon de le faire fonctionner de manière dynamique est d'appeler newInstance() après! Sinon, vous serez confronté à première vue inexplicable "SQLException: pas de pilote approprié". Une fois encore, il s'agit d'un bogue dans le pilote JDBC, pas dans votre propre code. De nos jours, aucun pilote JDBC ne devrait contenir ce bogue. Ainsi, vous pouvez (et devriez) laisser la newInstance() de côté.

28
BalusC

1: si vous ne vous intéressez qu'au bloc statique de la classe, le chargement de la classe seule suffirait et exécuterait des blocs statiques, il vous suffira de:

Class.forName("Somthing");

2: si vous êtes intéressé par le chargement de la classe, exécutez ses blocs statiques et souhaitez également accéder à sa partie non statique, vous avez besoin d'une instance et ensuite:

Class.forName("Somthing").newInstance();

Class.forName () obtient une référence à une classe. Class.forName (). NewInstance () essaie d'utiliser le constructeur no-arg pour que Class retourne une nouvelle instance.

6
Gopi

en ajoutant simplement aux réponses ci-dessus, lorsque nous avons un code statique (c’est-à-dire que le bloc de code est indépendant de toute instance) qui doit être présent en mémoire, nous pouvons renvoyer la classe afin que nous utilisions Class.forname ("someName") sinon si nous ne pas avoir de code statique, nous pouvons aller pour Class.forname (). newInstance ("someName"), car il va charger des blocs de code de niveau objet (non statique) à la mémoire

3
sij

"Class.forName ()" renvoie le type de classe pour le nom donné. "newInstance ()" renvoie une instance de cette classe.

Sur le type, vous ne pouvez appeler directement aucune méthode d'instance, mais vous ne pouvez utiliser que la réflexion pour la classe. Si vous voulez travailler avec un objet de la classe, vous devez en créer une instance (comme si vous appeliez "new MyClass ()").

Exemple pour "Class.forName ()"

Class myClass = Class.forName("test.MyClass");
System.out.println("Number of public methods: " + myClass.getMethods().length);

Exemple pour "Class.forName (). NewInstance ()"

MyClass myClass = (MyClass) Class.forName("test.MyClass").newInstance();
System.out.println("String representation of MyClass instance: " + myClass.toString());
3
Arne Deutsch

Class.forName () -> forName () est la méthode statique de la classe qui retourne un objet de classe utilisé pour la réflexion et non un objet de classe utilisateur. Vous ne pouvez donc y appeler que des méthodes de classe telles que getMethods (), getConstructors (), etc.

Si vous souhaitez uniquement exécuter un bloc statique de votre classe (à l'exécution donnée) et obtenir uniquement des informations sur les méthodes, les constructeurs, les modificateurs, etc. de votre classe, vous pouvez utiliser cet objet obtenu à l'aide de Class.forName ().

Mais si vous souhaitez accéder à votre méthode de classe ou l'appeler (classe que vous avez indiquée au moment de l'exécution), vous devez définir son objet afin que la méthode newInstance de la classe Class le fasse pour vous.Il crée une nouvelle instance de la classe et vous le renvoie. Vous avez juste besoin de le dactylographier à votre classe.

ex-: supposons que Employé soit votre classe alors

Classe a = Class.forName (args [0]);

// args [0] = argument de ligne de commande permettant de donner la classe à l'exécution.

Employé ob1 = a.newInstance ();

a.newInstance () est similaire à la création d'objet à l'aide de new Employee ().

vous pouvez maintenant accéder à tous les champs et méthodes visibles de votre classe.

0
Vinod Malkani