Explication détaillée de la réflexion Java
Cet article utilise toujours de petits exemples pour illustrer, car je pense toujours que le cas est le meilleur, sinon si vous ne lisez que la théorie, vous ne le comprendrez pas après l'avoir lu. Cependant, il est recommandé de regarder en arrière la théorie après avoir lu l'article et avoir une meilleure compréhension.
Le texte principal commence ci-dessous.
[Cas 1] Obtenez le package complet et le nom de classe via un objet
package reflète; / ** * Obtenez le nom complet du package et le nom de classe via un objet * * / class Demo {// Autres codes ...} classe Hello {public static void main (String [] args) {Demo Demo = new Demo (); System.out.println (Demo.getClass (). GetName ()); }}【Résultat d'exécution】: refléter.demo
Ajoutez une phrase: tous les objets de classes sont en fait des instances de classe.
【Cas 2】 Objet de classe instancielle
package reflète; class Demo {// Autres codes ...} classe Hello {public static void main (String [] args) {class <?> Demo1 = null; Classe <?> Demo2 = null; Classe <?> Demo3 = null; Essayez {// essayez généralement d'utiliser ce formulaire Demo1 = class.Forname ("Reflect.demo"); } catch (exception e) {e.printStackTrace (); } demo2 = new Demo (). GetClass (); Demo3 = Demo.class; System.out.println ("Nom de classe" + Demo1.getName ()); System.out.println ("Nom de classe" + Demo2.GetName ()); System.out.println ("Nom de classe" + Demo3.GetName ()); }}【Résultats de l'opération】:
Classe namereflect.demo
Classe namereflect.demo
Classe namereflect.demo
[Cas 3] Instancier des objets d'autres classes à travers la classe
Objets instanciés en construisant des non-paramètres
package reflète; classe de classe {public String getName () {return name; } public void setName (string name) {this.name = name; } public int getage () {return âge; } public void Setage (int Age) {this.age = age; } @Override public String toString () {return "[" + this.name + "" + this.age + "]"; } nom de chaîne privée; Âge privé; } class hello {public static void main (string [] args) {class <?> Demo = null; essayez {demo = class.forname ("reflète.person"); } catch (exception e) {e.printStackTrace (); } Personne par = null; essayez {per = (personne) Demo.NewInstance (); } Catch (InstantiationException E) {// TODO Block de capture généré par Auto E.PrintStackTrace (); } Catch (illégalaccessException e) {// Bloc de capture généré par Auto-généré e.PrintStackTrace (); } per.setName ("Rollen"); Per.Setage (20); System.out.println (par); }}【Résultats de l'opération】:
[Rotenn 20]
Mais notez que lorsque nous annulons le constructeur sans paramètre par défaut en personne, par exemple, après avoir défini un seul constructeur avec des paramètres, une erreur se produira:
Par exemple, j'ai défini un constructeur:
Personne publique (nom de la chaîne, int age) {this.age = age; this.name = name; }Continuez ensuite à exécuter le programme ci-dessus, et il apparaîtra:
java.lang.instantiationException: réflect.
sur java.lang.class.newinstance0 (class.java:340)
sur java.lang.class.newinstance (class.java:308)
at Reflect.hello.main (Hello.java:39)
Exception dans Thread "Main" java.lang.nullpointerException
at Reflect.hello.main (Hello.java:47)
Ainsi, lorsque vous écrivez des objets qui utilisent la classe pour instancier d'autres classes, vous devez définir votre propre constructeur sans paramètres.
[Cas] Appel des constructeurs dans d'autres classes via la classe (vous pouvez également créer des objets d'autres classes via la classe de cette manière)
package reflète; import java.lang.reflect.constructor; classe de classe {Public Person () {} Public Person (String Name) {this.name = name; } Personne publique (int Age) {this.age = Âge; } Personne publique (nom de la chaîne, int Age) {this.age = age; this.name = name; } public String getName () {Nom de retour; } public int getage () {return âge; } @Override public String toString () {return "[" + this.name + "" + this.age + "]"; } nom de chaîne privée; private int age;} class hello {public static void main (String [] args) {class <?> Demo = null; essayez {demo = class.forname ("reflète.person"); } catch (exception e) {e.printStackTrace (); } Personne per1 = null; Personne Per2 = null; Personne per3 = null; Personne per4 = null; // Obtenez tous les constructeurs constructeurs <?> CONS [] = DEMO.getConstructors (); essayez {per1 = (personne) contre [0] .newInstance (); Per2 = (personne) CONS [1] .Newinstance ("Roln"); Per3 = (personne) contre [2] .NewInstance (20); Per4 = (personne) CONS [3] .Newinstance ("Roln", 20); } catch (exception e) {e.printStackTrace (); } System.out.println (Per1); System.out.println (Per2); System.out.println (Per3); System.out.println (Per4); }}【Résultats de l'opération】:
[null 0]
[Rotenn 0]
[NULL 20]
[Rotenn 20]
【Cas】
Renvoie l'interface implémentée par une classe:
package reflète; interface china {public static final string name = "rollen"; L'âge du public statique = 20; public void saychina (); public void sayshello (nom de chaîne, int Âge);} la classe de classe implémente la Chine {Public Person () {} Public Person (String Sex) {this.sex = sexe; } public String getSEX () {return sexe; } public void setSex (String Sex) {this.sex = sexe; } @Override public void Saychina () {System.out.println ("Hello, China"); } @Override public void sayshello (nom de chaîne, int age) {System.out.println (nom + "" + âge); } private String Sex;} class Hello {public static void main (String [] args) {class <?> Demo = null; essayez {demo = class.forname ("reflète.person"); } catch (exception e) {e.printStackTrace (); } // Enregistrer toutes les interfaces Class <?> Ines [] = demo.getInterfaces (); for (int i = 0; i <entes.length; i ++) {System.out.println ("Interface implémentée" + entes [i] .getName ()); }}}【Résultats de l'opération】:
Interface implémentée Reflect.China
(Notez que les exemples suivants utiliseront la classe de personne de cet exemple, donc pour économiser de l'espace, nous ne collerons plus la partie du code de la personne ici, seulement le code de la classe principale bonjour)
【Case】: Obtenez la classe parent dans d'autres classes
class hello {public static void main (string [] args) {class <?> démo = null; essayez {demo = class.forname ("reflète.person"); } catch (exception e) {e.printStackTrace (); } // Obtenez la classe Parent Class <?> Temp = demo.getsuperclass (); System.out.println ("La classe parent héritée est:" + temp.getName ()); }}【Exécuter les résultats】
La classe parent héritée est: java.lang.object
【Case】: Obtenez tous les constructeurs dans d'autres classes
Cet exemple nécessite l'ajout d'importation java.lang.reflect. * Au début du programme;
Ensuite, écrivez la classe principale comme:
class hello {public static void main (string [] args) {class <?> démo = null; essayez {demo = class.forname ("reflète.person"); } catch (exception e) {e.printStackTrace (); } Constructor <?> CONS [] = DEMO.GETCONSTRUCTORS (); for (int i = 0; i <cons.length; i ++) {System.out.println ("Constructeur:" + contre [i]); }}}【Résultats de l'opération】:
Construction de la méthode: Public Reflect.Serson ()
Constructeur: Public Reflect.Serson (java.lang.string)
Mais les lecteurs prudents constateront que le constructeur ci-dessus n'a pas de modificateurs tels que le public ou le privé
Prenons le modificateur dans l'exemple suivant
class hello {public static void main (string [] args) {class <?> démo = null; essayez {demo = class.forname ("reflète.person"); } catch (exception e) {e.printStackTrace (); } Constructor <?> CONS [] = DEMO.GETCONSTRUCTORS (); for (int i = 0; i <cons.length; i ++) {class <?> p [] = contre [i] .getParameterTypes (); System.out.print ("Constructeur:"); int mo = contre [i] .getModificaires (); System.out.print (modificateur.tostring (MO) + ""); System.out.print (CONS [i] .getName ()); System.out.print ("("); for (int j = 0; j <p.length; ++ j) {System.out.print (p [j] .getName () + "arg" + i); if (j <p.length-1) {System.out.print (",");}} system.out.println (") {}"); }}【Résultats de l'opération】:
Constructeur: Public Reflect.person () {}
Constructeur: Public Reflect.person (java.lang.string arg1) {}
Parfois, il peut y avoir des exceptions dans une méthode, haha. Jetons un coup d'œil:
class hello {public static void main (string [] args) {class <?> démo = null; essayez {demo = class.forname ("reflète.person"); } catch (exception e) {e.printStackTrace (); } Méthode Méthode [] = DEMO.GetMethods (); for (int i = 0; i <méthode.length; ++ i) {class <?> returnType = méthode [i] .getReturnType (); Classe <?> Para [] = méthode [i] .getParameterTypes (); int temp = méthode [i] .getModificaires (); System.out.print (modificateur.tostring (temp) + ""); System.out.print (returnType.getName () + ""); System.out.print (méthode [i] .getName () + ""); System.out.print ("("); pour (int j = 0; j <para.length; ++ j) {System.out.print (para [j] .getName () + "" + "arg" + j); if (j <le.length-1) {System.out.print (",");}} classe <? if (exce.length> 0) {System.out.print (") lance"); for (int k = 0; k <exce.length; ++ k) {System.out.print (exce [k] .getName () + ""); if (k <exce.length-1) {System.out.print (","); }}} else {System.out.print (")"); } System.out.println (); }}}【Résultats de l'opération】:
public java.lang.string getsex ()
public void Setsex (java.lang.string arg0)
public void saychina ()
public void Sayshello (java.lang.string arg0, int arg1)
Public Final Native Void Wait (Long Arg0) lève Java.lang.InterruptedException
public final void wait () lève java.lang.interruptedException
Public Final Void Wait (Long Arg0, int arg1) lève java.lang.interruptedException
Public Boolean Equals (Java.lang.Object Arg0)
public java.lang.string toString ()
Public natif int hashcode ()
Public final natif java.lang.class getClass ()
Public Final Native Void Notify ()
Native void Native Notifyall () publique ()
[Cas] Ensuite, obtenons toutes les propriétés des autres classes. Enfin, je vais les régler ensemble, c'est-à-dire pour obtenir tout le cadre d'une classe à travers la classe
class hello {public static void main (string [] args) {class <?> démo = null; essayez {demo = class.forname ("reflète.person"); } catch (exception e) {e.printStackTrace (); } System.out.println("=========================================================================================== =============================================================================================================================. =============================================================================================================================. ==============================================================================================================================. Permission modificateur int mo = champ [i] .getModifiers (); string priv = modificier.toString (mo); System.out.println("====================================================================================== ============================================================================================================. ===========================================================================================================. ============================================================================================================. filed1 = demo.getFields (); pour (int j = 0; j <filed1.length; j ++) {// Modificateur d'autorisation int mo = filed1 [j] .getModifiers (); String priv = modificier.toString (mo); // Propriété Type Class <?> Type = filed1 [J] .getType (); System.out.println (priv + "" + type.getName () + "" + filed1 [j] .getName () + ";"); }}}【Résultats de l'opération】:
==============================================.
privé java.lang.string sexe;
====================================================================.
Public Static Final Java.lang.String Nom;
Int d'intm statique publique;
[Cas] En fait, les méthodes d'autres classes peuvent également être appelées par réflexion:
class hello {public static void main (string [] args) {class <?> démo = null; essayez {demo = class.forname ("reflète.person"); } catch (exception e) {e.printStackTrace (); } essayez {// appelant la méthode saychina dans la méthode de la classe de la personne = demo.getMethod ("saychina"); Method.invoke (Demo.NewInstance ()); // Appel de la méthode Sayhello de la personne = DEMO.GetMethod ("Sayhello", String.class, int.class); Method.invoke (Demo.NewInstance (), "Roln", 20); } catch (exception e) {e.printStackTrace (); }}}【Résultats de l'opération】:
Bonjour, Chine
Rotenn 20
【Case】 Ensemble d'appels et obtenez des méthodes d'autres classes
class hello {public static void main (string [] args) {class <?> démo = null; Objet obj = null; essayez {demo = class.forname ("reflète.person"); } catch (exception e) {e.printStackTrace (); } try {obj = demo.newinstance (); } catch (exception e) {e.printStackTrace (); } setter (obj, "sexe", "mâle", string.class); Getter (obj, "sexe"); } / ** * @param obj * Objet d'opération * @param att * Attributs de l'opération * * / public static void getter (objet obj, string att) {try {méthode méthode = obj.getClass (). getMethod ("get" + att); System.out.println (méthode.invoke (obj)); } catch (exception e) {e.printStackTrace (); }} / ** * @param obj * Objet de l'opération * @param att * Attributs de l'opération * @param Valeur * Set Value * @param Type * Attributs du paramètre * * / public static void setter (objet obj, string att, Object Value, classe <? Method.invoke (obj, valeur); } catch (exception e) {e.printStackTrace (); }}} // Classe finale【Résultats de l'opération】:
mâle
【Cas】 opération par réflexion
class hello {public static void main (String [] args) lève l'exception {class <?> Demo = null; Objet obj = null; Demo = class.Forname ("Reflect.person"); obj = demo.newinstance (); Field Field = Demo.getDeclaredField ("Sex"); field.setAccessible (true); field.set (obj, "mâle"); System.out.println (field.get (obj)); }} // Classe finale[Cas] Obtenez et modifiez les informations du tableau par réflexion:
import java.lang.reflect. *; class hello {public static void main (String [] args) {int [] temp = {1,2,3,4,5}; Class <?> Demo = temp.getClass (). GetComponentType (); System.out.println ("Type de tableau:" + demo.getName ()); System.out.println ("Longueur du tableau" + array.getLength (temp)); System.out.println ("premier élément du tableau:" + array.get (temp, 0)); Array.set (temp, 0, 100); System.out.println ("Après avoir modifié le premier élément du tableau est:" + array.get (temp, 0)); }}【Résultats de l'opération】:
Type de tableau: int
Longueur du tableau 5
Le premier élément du tableau: 1
Après modification, le premier élément du tableau est: 100
【Case】 Modifiez la taille du tableau par réflexion
classe Hello {public static void main (String [] args) {int [] temp = {1,2,3,4,5,6,7,8,9}; int [] newTemp = (int []) arrayinc (temp, 15); print (newTemp); System.out.println("=================================================================================== ==========================================================================================================. String []) ArrayInc (ATR, 8); System.ArrayCopy (obj, 0, NewAr, CO); Array.getLength (obj); i ++) {System.out.print (array.get (obj, i) + "");【Résultats de l'opération】:
La longueur du tableau est: 15
1 2 3 4 5 6 7 8 9 0 0 0 0 0 0 ====================================================.
La longueur du tableau est: 8
ABC null null null null null
Agent dynamique
[Cas] Tout d'abord, jetons un coup d'œil à l'obtention du chargeur de classe:
classe Test {} classe Hello {public static void main (String [] args) {test t = new test (); System.out.println ("classloader" + t.getClass (). GetClassLoader (). GetClass (). GetName ()); }}【Sortie du programme】:
Class Loder Sun.Misc.Launcher $ AppClassloadher
En fait, il existe trois types de chargeurs de classe en Java.
1) Bootstrap classloader Ce chargeur est écrit en C ++ et est rarement vu dans le développement général.
2) L'extension Classloader est utilisée pour charger des classes étendues, correspondant généralement aux classes dans JRE / LIB / EXT répertoire
3) AppClassloader charge la classe spécifiée par ClassPath et est le chargeur le plus couramment utilisé. C'est également le chargeur par défaut en Java.
Si vous souhaitez terminer un proxy dynamique, vous devez d'abord définir une sous-classe de l'interface InvocationHandler et le fonctionnement spécifique du proxy est terminé.
package reflète; import java.lang.reflect. *; // Définir l'interface du projet Sujet {public String Says (Nom de la chaîne, Int Age);} // Définir la classe de projet Real RealSubject implémente le sujet {@Override public String Says (Nom de la chaîne, int Age) {Nom de retour + "" + Age; }} class MyInvocationHandler implémente invocationhandler {private objet obj = null; objet public bind (objet obj) {this.obj = obj; return proxy.newProxyInstance (obj.getClass (). getClassOader (), obj .getClass (). getInterfaces (), this); } @Override Public Object Invoke (Proxy d'objet, méthode de la méthode, objet [] args) lève le throwable {objet temp = méthode.invoke (this.obj, args); Tempère de retour; }} classe Hello {public static void main (String [] args) {MyInvocationHandler Demo = new MyInvocationHandler (); Sujet sub = (sujet) Demo.Bind (new realSubject ()); String info = sub.say ("Rollen", 20); System.out.println (info); }}【Résultats de l'opération】:
Rotenn 20
Le cycle de vie d'une classe
Une fois une classe compilée, l'étape suivante consiste à commencer à utiliser la classe. Si vous souhaitez utiliser une classe, elle est définitivement inséparable de JVM. Pendant l'exécution du programme, le JVM est terminé via ces trois étapes: le chargement, la liaison et l'initialisation.
Le chargement de classe se fait via un chargeur de classe. Le chargeur charge le fichier binaire du fichier .class dans la zone de la méthode JVM et crée un objet java.lang.classe décrivant cette classe dans la zone du tas. Utilisé pour encapsuler les données. Mais la même classe ne sera chargée que par le chargeur de classe avant
Les liens doivent assembler des données binaires dans un état qui peut être exécuté.
Le lien est divisé en trois étapes: vérification, préparation et analyse
La vérification est généralement utilisée pour confirmer si ce fichier binaire convient au JVM actuel (version).
La préparation est d'allouer des espaces mémoire aux membres statiques. et définir les valeurs par défaut
L'analyse fait référence au processus de conversion du code dans le pool constant comme référence directe jusqu'à ce que toutes les références symboliques puissent être utilisées par le programme en cours d'exécution (établir une correspondance complète)
Une fois terminé, le type est initialisé. Après initialisation, l'objet de la classe peut être utilisé normalement. Une fois qu'un objet n'est plus utilisé, il sera collecté aux ordures. Espace libre.
Quand aucune référence ne pointe vers l'objet de classe, il ne sera pas en place, mettant fin au cycle de vie de la classe
Utiliser la réflexion pour le mode d'usine
Jetons un coup d'œil au mode d'usine si vous n'avez pas besoin de réflexion:
http://www.cnblogs.com/rollenholt/archive/2011/08/18/2144851.html
/ ** * @author Mode d'usine Rollen-Holt du modèle de conception * / Interface Fruit {public abstract void Eat ();} classe Apple implémente Fruit {public void Eat () {System.out.println ("Apple"); }} class Orange implémente fruit {public void Eat () {System.out.println ("orange"); }} // Construisez la classe d'usine // En d'autres termes, si nous n'avons besoin de modifier la classe d'usine lors de l'ajout d'autres instances dans la future classe Factory {public static fruit getInstance (String fruitName) {fruit f = null; if ("pomme" .equals (fruitName)) {f = new Apple (); } if ("orange" .equals (fruitName)) {f = new Orange (); } return f; }} classe bonjour {public static void main (String [] a) {fruit f = factory.getInstance ("orange"); exploit(); }}De cette façon, lorsque nous ajoutons une sous-classe, nous devons modifier la classe d'usine. Si nous ajoutons trop de sous-classes, nous changerons beaucoup.
Voyons maintenant le mécanisme de réflexion en utilisant:
package reflète; Interface Fruit {public abstract void Eat ();} classe Apple implémente les fruits {public void Eat () {System.out.println ("pomme"); }} class Orange implémente fruit {public void Eat () {System.out.println ("orange"); }} classe Factory {public static fruit getInstance (String className) {fruit f = null; essayez {f = (fruit) class.forname (className) .newInstance (); } catch (exception e) {e.printStackTrace (); } return f; }} classe Hello {public static void main (String [] a) {fruit f = factory.getInstance ("reflev.apple"); if (f! = null) {f.eat (); }}}Maintenant, même si nous ajoutons autant de sous-classes, la classe d'usine n'a pas besoin d'être modifiée.
Bien que l'amour ci-dessus puisse obtenir une instance de l'interface via la réflexion, il doit passer dans le package complet et le nom de la classe. De plus, les utilisateurs ne peuvent pas savoir combien de sous-classes peuvent être utilisées dans une interface, nous configurons donc les sous-classes requises sous forme de fichiers d'attribut.
Jetons un coup d'œil à: Mode d'usine combinant des fichiers d'attribut
Créez d'abord un fichier de ressources fruit.properties.
Le contenu est:
Apple = réfléchir
orange = réflect.Orange
Ensuite, écrivez le code de classe principale:
package reflète; import java.io. *; import java.util. *; Interface Fruit {public abstract void Eat ();} classe Apple implémente les fruits {public void Eat () {System.out.println ("pomme"); }} class Orange implémente fruit {public void Eat () {System.out.println ("orange"); }} // Opération Propriété Classe de fichiers init {Public Static Properties GetPro () lève FileLoTFoundException, ioException {Properties pro = new Properties (); Fichier f = nouveau fichier ("fruit.properties"); if (f.exists ()) {pro.load (new FileInputStream (f)); } else {pro.setProperty ("Apple", "reflev.apple"); pro.setProperty ("orange", "reflev.orange"); pro.store (nouveau fileoutputStream (f), "Classe de fruits"); } return pro; }} classe Factory {public static fruit getInstance (String className) {fruit f = null; essayez {f = (fruit) class.forname (className) .newInstance (); } catch (exception e) {e.printStackTrace (); } return f; }} classe Hello {public static void main (String [] a) lève filenotfoundException, ioException {Properties pro = init.getPro (); fruit f = factory.getInstance (pro.getProperty ("pomme")); if (f! = null) {f.eat (); }}}【Exécuter le résultat】: Apple
Ce qui précède est une explication détaillée du mécanisme de réflexion Java. Nous continuerons d'ajouter des informations pertinentes à l'avenir. Merci pour votre soutien à ce site!