OVH Cloud OVH Cloud

Reflexivité de JAVA

6 réponses
Avatar
Soon
Bonjour à tous

J'ai deux problèmes de reflexivité de JAVA.

Tout d'abord une déclaration tel que :

...
Toto maVariable = new Toto()
...

avec la classe Toto suivante :

public class Toto
{
public string name;

Toto()
{
name= new String(/* le nom de l'instance de la variable -> maVariable*/)
}
}

Comment est-il possible de recuperer le nom de la variable de l'instance
en cours ?

Ensuite autre probleme

void creerInstance(String nomDeLaVariable)
{
Object /* nomDeLaVariable */ = new Object();
....

}

Est il possible d'instancier une variable en lui donnant comme nom une
chaine de caractères passée en paramètre ?

Merci beaucoup.

Thierry

6 réponses

Avatar
Yves Martin
Soon writes:

Toto maVariable = new Toto()

public class Toto
{
public string name;

Toto()
{
name= new String(/* le nom de l'instance de la variable -> maVariable*/)
}
}

Comment est-il possible de recuperer le nom de la variable de
l'instance en cours ?


C'est impossible à ma connaissance...

Ensuite autre probleme

void creerInstance(String nomDeLaVariable)
{
Object /* nomDeLaVariable */ = new Object();
....

}

Est il possible d'instancier une variable en lui donnant comme nom une
chaine de caractères passée en paramètre ?


Les variables locales (comme dans ton exemple) sont anonymisées par
le compilateur qui utilise la pile de la JVM. Donc la réponse est
nom.

Mais je ne devine le but que tu recherches derrière tes questions,
peut-être qu'il y a un autre moyen d'atteindre le même but. En tout
cas les pistes que tu prends ne sont pas possibles d'après la
spécification de la JVM.

La seule chose que l'on peut faire:
- connaître le nom de classe d'une instance, parcourir sa hiérarchie
de classes et d'interface
- connaître les attributs et les méthodes d'une classe/interface

On ne peut modifier les noms des attributs et des méthodes, sauf à
générer dynamiquement le bytecode d'une classe (éventuellement en
compilant du source) dans un ClassLoader de la JVM - ce qui est
possible avec des bibliothèques de manipulation du bytecode.

Maintenant, tu peux très bien assurer que les objets que tu manipules
puisse stocker leur "nom" (qui n'est pas un nom de variable) avec une
pair setter/getter et un attribut.

Finallement que veux-tu faire avec tes noms de variables ? Il y a
peut-être un autre moyen ?

--
Yves Martin

Avatar
Soon
Finallement que veux-tu faire avec tes noms de variables ? Il y a
peut-être un autre moyen ?

En fait j'interface du Prolog avec mon programme JAVA via JPL. Or les

variables (ou les termes) prolog sont en fait les noms de variable JAVA.

exemple :

en Prolog p(A).

en java :

Variable A = new Variable(); // ici Variable = Variable prolog

jpl.query("p",A);

Donc si je veux faire une fonction "String getArgument()" qui saisit
l'argument, je voudrais ensuite créer une Variable (prolog) dont le nom
est la chaine entrée en argument.

Et vice versa pour l'autre problème.

Je sais bien que les identifiants que va gerer la JVM sont totalement
indépendants de ceux du code. Mais le problème est que le nom que
j'affecte à une variable JAVA est significatif dans mon programme.

Je ne vois pas d'autres solutions à mon problème ...

Est ce vraiment impossible de faire ça ?

Merci de vos contributions.

A+

Avatar
Yves Martin
Soon writes:

en java :

Variable A = new Variable(); // ici Variable = Variable prolog

jpl.query("p",A);

Est ce vraiment impossible de faire ça ?


Hum... j'ai fait du Prolog en classe mais je trouve cette façon
d'interfacer avec Java très très particulière. Peut-être intuitive
pour un Prologiste mais pas pour un Javaxeur...

Finallement si ton jpl.query est capable de récupérer le nom de
variable 'A' attribué à l'objet passé en argument, c'est que c'est
possible...

Et dans ce cas, c'est soit en Java et je ne connais pas, soit en
natif (JNI) et je ne suis pas assez callé dans ce domaine pour te
répondre.

Je ne savais pas que Prolog avait tant de succès pour qu'il y ait
autant d'interfaces en Java:
http://www.declarativa.com/interprolog/systems.htm

Je vais jeter un oeil aux sources de JPL, la réponse y est surement.


Au fait, en Prolog, une variable est une variable peu importe son
nom, c'est juste ? Donc si on utilise deux fois la même variable
(l'objet et non son nom), il s'agit bien de cette variable et Prolog
peut résoudre son prédicat peu importe son nom finallement...

Je suis sur que le bytecode généré à la compilation ne contient plus
le nom 'A' utilisé dans le source. Donc JPL n'utilise que les objets
'Variable' de façon anonyme, en s'assurant que le même objet utilisé
dans deux arguments différents d'un prédicat est la même variable.

Pour preuve, essaie de compiler et tester:
jpl.query("p", new Variable());

Cela doit fonctionner même si ta variable n'a pas de nom !

--
Yves Martin

Avatar
Soon
Je suis sur que le bytecode généré à la compilation ne contient plus
le nom 'A' utilisé dans le source. Donc JPL n'utilise que les objets
'Variable' de façon anonyme, en s'assurant que le même objet utilisé
dans deux arguments différents d'un prédicat est la même variable.



Oui, le fait d'instancier une variable prolog en JAVA en faisant new
Variable(), la JVM crée en fait son propre identifiant de variable
C'est la où est le problème ! Car lorsqu'il retourne
les résultats c'est une hashtable entre cette clé (la variable) et la
valeur d'unification. Le truc qui fait que c'est utilisable, c'est qu'on
retrouve la clé en faisant un get avec la variable A comme clé. Mais si
je parcours simplement ma hashtable les valeurs de clé ne sont plus
significatives. Et donc impossible de faire une fonction générique qui
affiche les résultats quelque soit la requête !

Pour preuve, essaie de compiler et tester:
jpl.query("p", new Variable());

Cela doit fonctionner même si ta variable n'a pas de nom !



Ca marche ... mais si on passe un prédicat à 2 variables, impossible de
savoir quelle est la valeur de l'une ou de l'autre variable.

Au pire j'ai une solution (pas trés jolie), j'etends la classe
Variable() à MyVariable() tel que:

MyVariable A = new MyVariable("A");

Ensuite je peut faire A.getName();

Mais bon pourquoi faire simple quand on peut faire compliqué ... ;-) Le
but et que j'aurais aimé simplifié en évitant de passer la chaine de
caractère au constructeur ... mais si c'est impossible .. tans pis !

Merci beaucoup pour vos contributions.

A+

Avatar
Yves Martin
Soon writes:

Oui, le fait d'instancier une variable prolog en JAVA en faisant new
Variable(), la JVM crée en fait son propre identifiant de variable
C'est la où est le problème ! Car lorsqu'il retourne
les résultats c'est une hashtable entre cette clé (la variable) et la
valeur d'unification. Le truc qui fait que c'est utilisable, c'est
qu'on retrouve la clé en faisant un get avec la variable A comme
clé. Mais si je parcours simplement ma hashtable les valeurs de clé ne
sont plus significatives. Et donc impossible de faire une fonction
générique qui affiche les résultats quelque soit la requête !


OK c'est clair

Pour preuve, essaie de compiler et tester:
jpl.query("p", new Variable());
Cela doit fonctionner même si ta variable n'a pas de nom !


Ca marche ... mais si on passe un prédicat à 2 variables, impossible
de savoir quelle est la valeur de l'une ou de l'autre variable.


Normal.

Au pire j'ai une solution (pas trés jolie), j'etends la classe
Variable() à MyVariable() tel que:

MyVariable A = new MyVariable("A");
Ensuite je peut faire A.getName();


C'est une solution... mais à mon avis si tu regardes comment est fait
l'objet 'Variable' tu dois trouver un mécanisme pour retrouver ta
référence.

Mais bon pourquoi faire simple quand on peut faire compliqué ... ;-)
Le but et que j'aurais aimé simplifié en évitant de passer la chaine
de caractère au constructeur ... mais si c'est impossible .. tans pis !


Côté 'réflexion', ce n'est pas possible, j'en suis presque sur.

Autre solution à ta disposition: deux Map nom->Variable et
Variable->nom

Quand tu crées une variable tu l'enregistres dans tes Map, ensuite tu
peux retrouver le nom ou la Variable avec l'autre objet.

Condition: que Variable implémente correctement equals ! Et d'après
le source, ça me semble bien fait.

--
Yves Martin


Avatar
dominique.dechamps
Thierry,

Pour ta première question, peut-être que le morceau de code ci-dessous
pourra-t'il t'inspirer, sachant que son but est de transférer les
valeurs de variables de même nom d'une classe à l'autre.

/*
* Introspect.java
* Created on May 31, 2003, 2:40 PM
* Copyright (C) 2000-2003 dominique dechamps
*
* http://dominique.dechamps.free.fr/JA/home.html
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
package JA.DynamicPatching.Swapper;

import JA.Examples.Componants.*;
import java.lang.reflect.*;
import java.security.*;

public class Introspect{
int iCOPIED=0;

public Introspect(Object oORI,Object oCOPY){
System.out.println("oORI hashCode="+oORI.hashCode()+" oCOPY
hashCode="+oCOPY.hashCode());
if (oORI instanceof
A){System.out.println("oORI="+((A)oORI).getBeforeName()+" with
X="+((A)oORI).getX()+" X*Y="+((A)oORI).getXY());}
Field[] fORI=oORI.getClass().getDeclaredFields();
Field[] fCOPY=oCOPY.getClass().getDeclaredFields();
int lORI=fORI.length;
int lCOPYüOPY.length;
copyFields(oORI,fORI,oCOPY,fCOPY);
Class superClassORI=oORI.getClass().getSuperclass();
Class superClassCOPY=oCOPY.getClass().getSuperclass();
//
W1:
while (superClassORI!=null &&
superClassCOPY!=null &&
superClassORI==superClassCOPY){
fORI =superClassORI.getDeclaredFields();
fCOPY=superClassCOPY.getDeclaredFields();
lORI=lORI+fORI.length;
copyFields(oORI,fORI,oCOPY,fCOPY);
superClassORI=superClassORI.getSuperclass();
superClassCOPY=superClassCOPY.getSuperclass();
}
//
oORI=oCOPY;
System.out.println("ORI Fields#="+lORI+" COPIED Fields#="+iCOPIED);
System.out.println("oORI hashCode="+oORI.hashCode()+" oCOPY
hashCode="+oCOPY.hashCode());
if (oORI instanceof
A_PRIME){System.out.println("oORI="+((A_PRIME)oORI).getAspectName()+"
with X="+((A_PRIME)oORI).getX()+" with Y="+((A_PRIME)oORI).getY()+"
X*Y="+((A_PRIME)oORI).getXY());}
}

/**
* Thanks to Renaud Pawlak for his idea
* http://jac.aopsys.com/
*/
private void copyFields(final Object oORI, final Field[] fORI,
final Object oCOPY,final Field[] fCOPY){
AccessController.doPrivileged(
new PrivilegedAction() {
public Object run() {
AccessibleObject.setAccessible(fORI, true );
AccessibleObject.setAccessible(fCOPY, true );
F1:
for (int i=0;i<fORI.length;i++){
try{
F2:
for (int j=0;j<fCOPY.length;j++){
if (!fCOPY[j].getName().equals(fORI[i].getName()))
{continue F2;}
fCOPY[j].set(oCOPY,fORI[i].get(oORI));
iCOPIED++;
System.out.println("Original["+oORI.getClass().getName().substring("JA.Examples.Componants.".length())+"]["+fORI[i].getName()+"]["+fORI[i].getType()+"]="+fORI[i].get(oORI).toString()+"
=> Copy["+oCOPY.getClass().getName().substring("JA.Examples.Componants.".length())+"]["+fCOPY[j].getName()+"]["+fCOPY[j].getType()+"]="+fCOPY[j].get(oCOPY).toString());
break F2;
}//F2
}//try
catch (Exception e){e.printStackTrace();}
}//F1
return null;
}//run
}//PrivilegedAction

);//AccessController
}//introspect

public static void main(String[] args){
A a=new A(1,2,"I AM A");
A_PRIME a_prime=new A_PRIME(-1,-1,"I AM A'");
Introspect intro=new Introspect(a,a_prime);
}
}

/////////////////
Pour ta deuxième question s'il y a une possibilité voir
http://www.csg.is.titech.ac.jp/~chiba/javassist/
mais je suis comme les autres intervenants cela me semble impossible

Dominique