Quelle est la différence entre "Classe.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 sur eux!). Pourriez-vous m'aider?

144
demandé sur nbro 2010-01-19 13:11:38

8 réponses

peut-être qu'un exemple démontrant comment les deux méthodes sont utilisées vous aidera à mieux comprendre les choses. Ainsi, 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 javadoc, appelant Class.forName(String) renvoie l'objet Class associé à la classe ou à l'interface avec le nom de chaîne de caractères , c'est-à-dire qu'il renvoie test.Demo.class qui est affecté à la variable clazz de type Class .

alors, 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 par une expression new avec une liste d'arguments vide. en d'autres termes, ceci est en fait équivalent à un new Demo() et renvoie une nouvelle instance de Demo .

et l'exécution de cette classe Demo imprime ainsi la suivante sortie:

Hi!

la grande différence avec le traditionnel new est que newInstance permet d'instancier une classe que vous ne connaissez pas jusqu'à l'exécution, rendant votre code plus dynamique.

un exemple typique est L'API JDBC qui charge, à l'exécution, le pilote exact requis pour effectuer le travail. Les conteneurs EJBs, les conteneurs Servlet en sont d'autres bons exemples: ils utilisent le chargement dynamique pour charger et créer des composants qu'ils n'utilisent pas. sais quoi avant le moment de l'exécution.

en fait, si vous voulez aller plus loin, jetez un oeil à Ted Neward papier classe de compréhension.forName () que je paraphrasais dans le paragraphe ci-dessus.

EDIT (répondant à une question de L'OP postée comme commentaire): le cas des pilotes JDBC est un peu spécial. Comme expliqué dans le DriverManager chapitre de obtenir A commencé avec L'API JDBC :

(...) Une classe Driver est chargée, et donc automatiquement enregistré avec le DriverManager , dans l'un des deux façons:

  1. en appelant la méthode Class.forName . Cela charge explicitement le pilote de la classe. Depuis, il n'a pas dépendent externes de l'installation, de cette façon de charger un conducteur est le recommandé un pour utiliser le DriverManager Framework. Les charges de code suivantes la classe acme.db.Driver :

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

    si acme.db.Driver a été écrit de sorte que le chargement il provoque un instance à créer et aussi appels DriverManager.registerDriver avec cette exemple le paramètre (comme il devrait faire), alors il est dans le DriverManager liste des pilotes et disponible pour créer une connexion.

  2. (...)

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

pour s'enregistrer lors de l'initialisation, le pilote JDBC utilise généralement un bloc d'initialisation statique comme ceci:

package acme.db;

public class Driver {

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

    ...
}

appelant Class.forName("acme.db.Driver") provoque le 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 c'est juste une conséquence de la façon dont le (bon) pilote JDBC est implémenté.

comme note, je mentionnerais 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 JDBC 4.0 améliorations en Java SE 6 .

209
répondu Pascal Thivent 2016-03-03 19:27:50

de la Classe.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 chaque classe. Appeler newInstance () sur cela vous donne une instance de cette classe (i.e. appeler Class.forName("ExampleClass").newInstance() c'est équivalent à appeler new ExampleClass() ), sur laquelle vous pouvez appeler les méthodes que la classe définit, accéder aux champs visibles, etc.

34
répondu Thomas Lötzer 2010-01-19 10:22:42

dans JDBC world, la pratique normale (selon L'API JDBC) est que vous utilisez Class#forName() pour charger un pilote JDBC. Le pilote JDBC devrait notamment s'enregistrer dans DriverManager à l'intérieur d'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() {
        //
    }

}

invoquant Class#forName() exécutera tous les initialisateurs statiques . De cette façon, le DriverManager peut trouver le conducteur associé parmi les conducteurs enregistrés par URL de connexion pendant getConnection() qui ressemble à peu près comme 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 buggy pilotes JDBC, à partir du org.gjt.mm.mysql.Driver comme exemple bien connu, qui s'inscrit incorrectement à l'intérieur du 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 dynamiquement est d'appeler newInstance() par la suite! Dans le cas contraire, vous serez confrontés à première vue inexplicable "SQLException: no suitable driver". Encore une fois, c'est un bug 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 le newInstance() à l'écart.

28
répondu BalusC 2017-05-23 11:54:56

1: si vous êtes intéressé seulement dans le bloc statique de la classe, le chargement de la classe seulement ferait , et exécuterait des blocs statiques alors tout ce que vous avez besoin est:

Class.forName("Somthing");

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

Class.forName("Somthing").newInstance();
12
répondu Hussain Akhtar Wahid 'Ghouri' 2015-04-30 01:51:28

de la Classe.forName () obtient une référence à une classe, Class.forName ().newInstance () essaie d'utiliser le constructeur no-arg pour que la classe renvoie une nouvelle instance.

6
répondu Gopi 2010-01-19 10:16:38

"de la Classe.forName () " renvoie le Type de classe pour le prénom. "newInstance()" retourne une instance de cette classe.

sur le type que vous ne pouvez appeler directement aucune méthode d'instance, mais que 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 appeler "new MyClass()").

exemple de" classe.forName () "

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

exemple pour "Classe.forName ().newInstance () "

MyClass myClass = (MyClass) Class.forName("test.MyClass").newInstance();
System.out.println("String representation of MyClass instance: " + myClass.toString());
3
répondu Arne Deutsch 2010-01-19 10:22:37

juste en ajoutant aux réponses ci-dessus, quand nous avons un code statique (i.e. Code block est indépendant de l'instance) qui doit être présent dans la mémoire, nous pouvons avoir la classe retournée afin que nous utilisions la classe.forname ("someName") sinon, si nous n'avons pas de code statique, nous pouvons choisir la classe.forname ().nouvelle instance ("nomename") puisqu'elle chargera des blocs de code (non statiques) au niveau de l'objet en mémoire

3
répondu sij 2011-03-16 08:21:12

de la Classe.forName ()-- > forName () est la méthode statique de la classe class,elle renvoie L'objet de la classe utilisé pour la réflexion et non l'objet de la classe user, de sorte que vous pouvez seulement appeler les méthodes de la classe Class comme getMethods (), getConstructors (), etc.

si vous vous souciez seulement d'exécuter un bloc statique de votre classe(Runtime donné) et d'obtenir des informations sur les méthodes,les constructeurs,le modificateur etc de votre classe, vous pouvez faire avec cet objet que vous obtenez en utilisant la classe.forName ()

mais si vous voulez accéder ou appeler votre méthode de classe (classe que vous avez donnée à l'exécution) alors vous devez avoir son objet si nouvelle méthode d'instance de classe le faire pour vous.Il crée une nouvelle instance de la classe et vous la renvoie .Vous avez juste besoin de type-cast-le à votre classe.

ex-: supposons que L'employé est votre classe alors

Classe A = Classe.forName (args[0]);

/ / args[0] = argument de ligne cmd pour donner la classe at Runtime.

employé ob1=a. newInstance ();

A. newInstance () est similaire à creating object using new Employee ().

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

0
répondu Vinod Malkani 2016-03-11 18:03:24