Class

publicité
Java et la réflexivité
Java reflection is useful because it supports dynamic retrieval
of information about classes and data structures by name, and allows
for their manipulation within an executing Java program.
This feature is extremely powerful and has no equivalent in other
conventional languages such as C, C++, Fortran, or Pascal.
Glen McCluskey
has focused on programming languages since 1988.
He consults in the areas of Java and C++ performance,
testing, and technical documentation.
Réflexivité en Java ?
La réflexivité en Java permet
à un programme Java de s’examiner en cours d’exécution
de manipuler ses propriétés internes.
Par exemple, une classe Java peut obtenir le nom de tous ses
membres.
Utilisation connue de la réflexivité : la composition visuelle de
Beans
L’outil utilise la réflexivité pour obtenir les propriétés des
composants (classes) lorsqu’ils sont dynamiquement chargés.
Que peut on faire ?
Obtenir des informations sur les classes
Simuler l’opérateur instanceof
Découvrir la liste et le descriptif des méthodes
Obtenir des informations sur les constructeurs
Avoir des informations sur les variables
Invoquer des méthodes, des constructeurs, affecter des variables
Créer des objets et des tableaux
dynamiquement lors de l ’exécution du programme
sans connaître à la compilation
le nom et les arguments d’une méthode / constructeur
le nom de la variable
le type des objets, des tableaux….
Réflexivité = un package Java
java.lang.reflect.*
des classes:
Object
Modifier
AccessibleObject
Constructor
ReflectPermission
InvocationTargetException
Field
Array
Method
une interface :
Member
Un exemple simple
public class DumpMethods {
public static void main(String args[])
{ try {
Class c = Class.forName(args[0]);
Method m[] = c.getDeclaredMethods();
for (int i = 0; i < m.length; i++)
System.out.println(m[i].toString());
}
catch (Throwable e) {System.err.println(e);}
}
}
java.util.Stack
public java.lang.Object java.util.Stack.push(java.lang.Object)
public synchronized java.lang.Object java.util.Stack.pop()
public synchronized java.lang.Object java.util.Stack.peek()
public boolean java.util.Stack.empty()
public synchronized int java.util.Stack.search(java.lang.Object)
Oui mais comment ?
Comment travailler avec les classes du package reflect ?
Obtenir un objet java.lang.Class
Récupérer des informations sur la classe
Utiliser l’API de reflect
Illustration à partir de l’exemple
Classe Class
Les instances de Class représentent les classes et les interfaces
d’une application Java.
Tous les tableaux sont aussi instances de Class (type des éléments,
dimension).
Les types primitifs (boolean, byte, char, short, int, long, float, double) et
le mot clé void sont aussi des objets Class.
Cette classe n’a pas de constructeur public.
Les instances sont créées automatiquement par la VM lorsque les classes
sont chargées et par la méthode defineClass des class loader.
Obtenir un objet java.lang.Class
représentant de la classe que l’on veut manipuler :
Pour les types fondamentaux
Class c = int.class;
ou
Class c = Integer.TYPE;
TYPE est une variable prédéfinie du wrapper (Integer, par exemple)
du type fondamental.
Pour les autres classes
Class c = Class.forName("java.lang.String");
Récupérer des informations sur la
classe
Appeler une méthode sur l’objet classe récupéré :
getDeclaredMethods : pour obtenir la liste de toutes les méthodes
déclarées dans la classe
getConstructors : pour obtenir la liste des constructeurs dans
la classe
getDeclaredFields : pour obtenir la liste des variables déclarées dans la
classe (quelque soit l’accesseur et non héritée)
getFields : pour obtenir la liste des variables publiques accessibles
....
Utiliser l’API de reflect
pour manipuler l’information
Par exemple :
Class c = Class.forName("java.lang.String");
Method m[] = c.getDeclaredMethods();
System.out.println(m[0])
.toString());
Comment Simuler l’opérateur instanceOf
Il existe une Classe A
et on veut vérifier si certaines instances sont de cette classe ou pas.
public class instance1 {
public static void main(String args[])
{try {Class cls = Class.forName("A");
boolean b1 = cls.isInstance(new Integer(37));
System.out.println(b1);
FALSE
boolean b2 = cls.isInstance(new A());
System.out.println(b2);
TRUE
}
catch (Throwable e) {System.err.println(e)}
}
}
classe AccessibleObject et
interface Member
AccessibleObject : Classe de base de Field, Method et Constructor.
Permet de supprimer ou de valider la vérification faite par défaut
concernant les contrôles d’accès.
Ces vérifications (sur private, public, package..) sont effectuées
lorsqu’on affecte ou lit des champs, lorsqu’on invoque une méthode
et lorsqu’on crée une instance.
Member : interface qui réifie les informations communes à un membre
(champ ou méthode) ou à un constructeur.
Classes Method, Field et
Constructor
Method fournit les informations et les accès à une méthode
(de classe, d’instance ou abstraite) d’une classe ou d’une interface.
Field fournit les informations et accès dynamiques aux champs (static
ou d’instances) d’une classe ou d’une interface.
Constructor fournit des informations et des accès à un
constructeur d’une classe.
Les méthodes d’une classe ?
1.
récupérer l ’objet Class que l’on souhaite observer,
2.
récupérer la liste des objets Method par getDeclaredMethods :
méthodes définies dans cette classe (public, protected, package, et
private)
getMethods permet d’obtenir aussi les informations concernant les
méthodes héritées
3.
A partir des objets méthodes il est facile de récupérer :
les types de paramètres, les types d’exception, et le type de
l’argument retourné sous la forme d’un type fondamental ou
d’un objet classe.
Exemple de programme
Class cls = Class.forName("method1");
Method methlist[] = cls.getDeclaredMethods();
for (int i = 0; i < methlist.length; i++) {
Method m = methlist[i];
System.out.println("name = " + m.getName());
System.out.println("decl class = " + m.getDeclaringClass());
Class pvec[] = m.getParameterTypes();
for (int j = 0; j < pvec.length; j++)
System.out.println("param #" + j + " " + pvec[j]);
Class evec[] = m.getExceptionTypes();
for (int j = 0; j < evec.length; j++)
System.out.println("exc #" + j + " " + evec[j]);
System.out.println("return type = " + m.getReturnType());}
Exemple d’exécution
public class method1 {
private int f1(Object p, int x) throws NullPointerException
{……..}
public static void main(String args[]) {….}
name = f1
decl class = class method1
param #0 class java.lang.Object
param #1 int
exc #0 class java.lang.NullPointerException
return type = int
name = main
decl class = class method1
param #0 class java.lang.String
return type = void
Informations sur les constructeurs
Les constructeurs sont similaires aux méthodes
mais ne renvoient pas de résultat
Découverte des variables
Similaire à la découverte de méthodes et de constructeurs.
l’utilisation de la classe Modifier.
Modifier représente les modifiers des variables (private int ...).
Ils sont eux mêmes représentés par un integer,
Modifier.toString renvoie la chaine correspondant à l’ordre « officiel »
("static" avant "final").
On peut obtenir les informations sur les variables définies dans
les super classes par getFields.
Invocation des méthodes par leur
nom
Equivalent du apply de Scheme
pour invoquer une méthode m dont le nom est spécifié à l’exécution
(dans le cadre de l’environnement de développement des
JavaBeans par exemple)
1.
Trouver une méthode dans une classe getMethod à partir
des types de ses paramètres et de son nom.
2.
La stocker dans un objet Method
3.
Construire la liste des paramètres d’appel
4.
Faire l’appel
Si on manipule un type fondamental à l’appel ou au retour
l’encapsuler dans la classe correspondante (int , Integer)
Exemple de programme
Class cls = Class.forName("method2");
Class partypes[] = new Class[2];
partypes[0] = Integer.TYPE;
partypes[1] = Integer.TYPE;
Method meth = cls.getMethod("add",partypes);
method2 methobj = new method2();
Object arglist[] = new Object[2];
arglist[0] = new Integer(37);
arglist[1] = new Integer(47);
Object retobj = meth.invoke(methobj, arglist);
Integer retval = (Integer)retobj;
System.out.println(retval.intValue())
Exemple d’exécution
public class method2 {
public int add(int a, int b)
{
return a + b;
}
public static void main(String args[])
{……
……
}
?
Création de nouveaux objets
Invoquer un constructeur implique de créer un nouvel objet
(allouer de la mémoire et construire l’objet)
1.
2.
Trouver un constructeur qui accepte les types spécifiés
L’invoquer
Création purement dynamique avec recherche (lookup) du constructeur
et invocation à l’exécution et non à la compilation.
Utilisation des tableaux
Création et manipulation des tableaux.
Array = un type spécial de classe
Le type du tableau qui est créé est dynamique et n’a pas besoin
d’être connu à la compilation
Réflexivité = un package Java
java.lang.reflect.*
des classes:
Object
Modifier
AccessibleObject
Constructor
ReflectPermission
InvocationTargetException
Field
Array
Method
une interface :
Member
Exemples concrets d’applications
Je vous écoute …….
Un peu plus de réflexivité
Les ClassLoader ????
Classe ClassLoader
ClassLoader est une classe abstraite.
Un class loader est un objet responsable du chargement des classes
Un nom de classe donné, il peut localiser ou générer les données qui
constituent une définition de la classe.
Chaque objet Class a une référence à un ClassLoader qui le définit.
Applications implémentent des sous classes de ClassLoader afin
d’étendre la façon de dynamiquement charger des classes par la VM.
(utilisation de manager de sécurité, par exemple)
Le chargement fonctionne par délégation
ClassLoader ?
En UNIX la VM charge les classes à partir des chemins définis dans
CLASSPATH (checkClassPath sous VA).
Certaines classes peuvent être obtenues à partir d’autres sources,
telles que le réseau ou construite par une application. La méthode
defineClass convertit un tableau d’octets en une instance de Class.
Instances pouvant être créées grâce à newInstance
Les méthodes et constructeurs créés par un class loader
peuvent référencer d’autres classes
(loadClass du class loader de cette classe).
Exemple de chargement de classe
Un class loader qui permet de charger des fichiers de classes via
le réseau
ClassLoader loader=new NetworkClassLoader(host,port);
Object main= loader.loadClass("Main", true).newInstance();
….
NetworkClassLoader doit définir findClass et loadClassData pour
charger et defineClass pour créer une instance de Class.
NetworkClassLoader
class NetworkClassLoader extends ClassLoader {
String host;
int port;
public Class findClass(String name) {
byte[] b = loadClassData(name);
return defineClass(name, b, 0, b.length);
}
private byte[] loadClassData(String name) {
// load the class data from the connection
…..
}}
Conclusion
Je vous écoute ….
Quelques Informations utiles sur
la sérialisation Java
Sérialisation-Desérialisation
• Enregistrer ou récupérer des objets dans un
flux
– Persistance
– Transfert sur le réseau
Sérialisation
• Via la méthode writeObject()
– Classe implémentant l’interface OutputObject
– Exemple : la classe OutputObjectStream
– Sérialisation d’un objet -> sérialisation de tous
les objets contenus par cet objets
• Un objet est sauvé qu’une fois : cache pour les listes
circulaires
Desérialisation
• Via la méthode readObject()
– Classe implémentant l’interface InputObject
– Exemple : la classe InputObjectStream
Exception NotSerializableException
• Si la classe de l’objet sauvé
– N’étend ni l’interface Java Serializable
– Ni l’interface Java Externalizable
Interface Serializable
• Ne contient pas de méthode
• -> enregistrement et récupération de toutes
les variables d’instances (pas de static)
+ informations sur sa classe (nom, version), type
et nom des variables
• 2 classes compatibles peuvent être utilisées
Objet récupéré = une copie de l’objet enregistré •
Gestion de la sérialisation
desérialisation
• Implémenter les méthodes
• private void writeObject(OutputObjectStream s) throws IOException
• private void readObject(OutputInputStream s) throws IOException
• defaultReadObject() et defaultWriteObject() méthodes par défaut
• Ajout d’informations à l’enregistrement, choix de
sérialisation
• Seulement pour les champs propres de la classe
(héritage géré automatiquement)
Gestion complète de la sérialisation
desérialisation : utiliser
Externalizable
• Graphe d’héritage complet
• Implémenter les méthodes
• public void writeExternal(ObjectOutput o) throws
IOException
• public void readExternal(ObjectInput o) throws
IOException
– ATTENTION PBM de SECURITE
Téléchargement