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?
Peut-être qu'un exemple montrant comment les deux méthodes sont utilisées vous aidera à mieux comprendre les choses. Alors, considérez 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, l'appel renvoie l' objet associé à la classe ou à l'interface avec le nom de chaîne donné, c'est-à-dire qu'il renvoie ce qui est affecté à la variable de type .Class.forName(String)
Class
test.Demo.class
clazz
Class
Ensuite, l'appel crée une nouvelle instance de la classe représentée par cet objet. La classe est instanciée comme par une expression avec une liste d'arguments vide. En d'autres termes, c'est ici en fait équivalent à a et renvoie une nouvelle instance de .clazz.newInstance()
Class
new
new Demo()
Demo
Et exécuter cette Demo
classe imprime ainsi la sortie suivante:
Hi!
La grande différence avec le traditionnel new
est que cela newInstance
permet d'instancier une classe que vous ne connaissez pas avant 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 à l'exécution pour charger et créer des composants dont ils ne savent rien avant l'exécution.
En fait, si vous voulez aller plus loin, jetez un œil à l'article de Ted Neward Understanding Class.forName () que je paraphrasais dans le paragraphe juste au-dessus.
EDIT (répondant à une question de l'OP postée en commentaire): Le cas des pilotes JDBC est un peu particulier. Comme expliqué dans le chapitre DriverManager de Premiers pas avec l'API JDBC :
(...) Une
Driver
classe est chargée, et donc automatiquement enregistrée avec leDriverManager
, de l'une des deux manières suivantes:
en appelant la méthode
Class.forName
. Cela charge explicitement la classe de pilote. Comme il ne dépend d'aucune configuration externe, cette façon de charger un pilote est celle recommandée pour l'utilisation duDriverManager
framework. Le code suivant charge la classeacme.db.Driver
:Class.forName("acme.db.Driver");
Si
acme.db.Driver
a été écrit de façon à ce que le chargement provoque la création d'une instance et appelle égalementDriverManager.registerDriver
cette instance comme paramètre (comme il se doit), alors il est dans laDriverManager
liste des pilotes et disponible pour créer une connexion.(...)
Dans ces deux cas, il est de la responsabilité de la
Driver
classe nouvellement chargée de s'enregistrer en appelantDriverManager.registerDriver
. Comme mentionné, cela devrait ê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 celui-ci:
package acme.db;
public class Driver {
static {
java.sql.DriverManager.registerDriver(new Driver());
}
...
}
L'appel Class.forName("acme.db.Driver")
provoque l'initialisation de la acme.db.Driver
classe et donc l'exécution du bloc d'initialisation statique. Et Class.forName("acme.db.Driver")
va effectivement "créer" une instance, mais ce n'est qu'une conséquence de la façon dont les (bons) pilotes JDBC sont implémentés.
En remarque, je mentionnerais que tout cela n'est plus nécessaire avec JDBC 4.0 (ajouté comme package par défaut depuis Java 7) et la nouvelle fonctionnalité de chargement automatique des pilotes JDBC 4.0. Voir les améliorations de JDBC 4.0 dans Java SE 6 .
DriverManager.registerDriver
. L'appelClass.forName
sur un pilote JDBC provoque son initialisation et donc l'exécution du bloc statique. Jetez un œil à java2s.com/Open-Source/Java-Document/Database-DBMS/… pour un exemple. C'est donc un cas particulier en raison des composants internes du pilote.Class.forName () vous donne l'objet de classe, ce qui est utile pour la réflexion. Les méthodes de cet objet sont définies par Java, pas 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 (c'est-à-dire que l'appeler
Class.forName("ExampleClass").newInstance()
équivaut à appelernew ExampleClass()
), sur laquelle vous pouvez appeler les méthodes que la classe définit, accéder aux champs visibles, etc.la source
Dans le monde JDBC, la pratique normale (selon l'API JDBC) est que vous utilisez
Class#forName()
pour charger un pilote JDBC. Le pilote JDBC doit notamment s'enregistrer dansDriverManager
un bloc statique:L'appel
Class#forName()
exécutera tous les initialiseurs statiques . De cette façon, vousDriverManager
pouvez trouver le pilote associé parmi les pilotes enregistrés par URL de connexion au cours degetConnection()
laquelle ressemblent à peu près à ce qui suit:Mais il y avait aussi bogué pilotes JDBC, en commençant par l'
org.gjt.mm.mysql.Driver
exemple aussi bien connu, qui s'enregistre de manière incorrecte à l' intérieur du constructeur au lieu d'un bloc statique:La seule façon de le faire fonctionner dynamiquement est d'appeler
newInstance()
après! Sinon, vous serez confronté à première vue "SQLException inexplicable: pas de pilote approprié". Encore une fois, 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 denewInstance()
côté.la source
1: si vous êtes intéressé uniquement par le bloc statique de la classe, le chargement de la classe ne ferait que faire, et exécuterait des blocs statiques alors tout ce dont vous avez besoin est:
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, alors vous avez besoin d'une instance et vous avez besoin de:
la source
Class.forName () obtient une référence à une classe, Class.forName (). NewInstance () essaie d'utiliser le constructeur sans argument pour que la classe retourne une nouvelle instance.
la source
"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 pouvez uniquement utiliser la réflexion pour la classe. Si vous voulez travailler avec un objet de la classe, vous devez en créer une instance (comme pour appeler "new MyClass ()").
Exemple pour "Class.forName ()"
Exemple pour "Class.forName (). NewInstance ()"
la source
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 l'instance) qui doit être présent en mémoire, nous pouvons avoir la classe retournée donc nous utiliserons Class.forname ("someName") sinon si nous ne pas avoir de code statique, nous pouvons utiliser Class.forname (). newInstance ("someName") car il chargera des blocs de code de niveau objet (non statiques) en mémoire
la source
Peu importe le nombre de fois que vous appelez la méthode Class.forName (), Une fois que le bloc statique est exécuté, pas plusieurs fois:
classe publique MainClass {
}
public class DemoClass {
}
la sortie sera:
in Static block in Instance block
Cette
in Static block
déclaration est imprimée une seule fois pas trois fois.la source
Class.forName () -> forName () est la méthode statique de la classe Class, elle retourne un objet de classe Class utilisé pour la réflexion et non un objet de classe utilisateur, vous ne pouvez donc appeler que des méthodes de classe Class comme getMethods (), getConstructors () etc.
Si vous vous souciez d'exécuter uniquement le bloc statique de votre classe (Runtime donné) et d'obtenir uniquement des informations sur les méthodes, les constructeurs, le modificateur, etc. de votre classe, vous pouvez le faire avec cet objet que vous obtenez en utilisant Class.forName ()
Mais si vous voulez accéder ou appeler votre méthode de classe (classe que vous avez donnée au moment de l'exécution), vous devez avoir 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 la renvoie Il vous suffit de le transtyper dans votre classe.
ex-: supposons que l'employé soit votre classe alors
Classe a = Class.forName (args [0]);
// args [0] = argument de ligne cmd pour donner la classe à l'exécution.
Employé ob1 = a.newInstance ();
a.newInstance () est similaire à la création d'un objet à l'aide de new Employee ().
vous pouvez maintenant accéder à tous les champs et méthodes visibles de votre classe.
la source