ReferenceHandler.java

import java.lang.reflect.*;
import java.util.*;
/**
 * Classe associant un handler (identificateur) unique pour chaque
 * référence accessible à partir d'un objet donné.
 */
public class ReferenceHandler {
  /** Valeur servant à numéroter les handlers. */ 
  private int handler = 0;
  /** Stocke les associations (comparaisons avec égalité primitive). */ 
  private IdentityHashMap map;
  /** Construit une instance associant des handlers aux références. */ 
  public ReferenceHandler() {
    map = new IdentityHashMap();
  }
  /** Calcule les handlers associés aux objets accessibles par o. */
  public void traverse(Object o) {
    if (o!=null) traverse(o, o.getClass());
  }
  /** Retourne l'ensemble des associations (référence, handler). */
  public Set getHandlers() { return map.entrySet(); }
  /** Associe des handlers aux objets accessibles par o de classe c. */
  private void traverse(Object o, Class c) {
    // Si o est de type primitif, on s'arrête
    if (c.isPrimitive()) return;
    // Si l'objet existe déjà (a déjà été rencontré), on s'arrête
    if (map.containsKey(o)) return;
    // Sinon on l'associe à un nouveau numéro de handler
    map.put(o, new Integer(handler++));
    // Si o est de type tableau
    if (c.isArray()) {
      // Si éléments de type primitif, on s'arrête
      if (c.getComponentType().isPrimitive()) return;
      // Sinon on parcourt récursivement chaque élément du tableau
      int length = Array.getLength(o);
      for (int i = 0; i<length; i++) {
    Object value = Array.get(o, i);
    if (value!=null) traverse(value, value.getClass());
      }
      return;
    }
    // Pour chaque classe (mère) de l'arbre d'héritage de c
    for (; c!=null; c=c.getSuperclass()) {
      // On recupère les champs déclarés
      Field[] fields = c.getDeclaredFields();
      // On autorise l'accès aux champs privés
      AccessibleObject.setAccessible(fields, true);
      for (int i=0; i<fields.length; i++) {
    Field field = fields[i];
    
        // Si le champ n'est pas statique et pas de type primitif
    if (!Modifier.isStatic(field.getModifiers())
        && !field.getType().isPrimitive()) {
      Object value = null;
      try {
        value = field.get(o); // On récupère la valeur du champ
      } catch (IllegalAccessException e) { e.printStackTrace(); }
          // Si non null, on traverse récursivement l'objet obtenu
      if (value != null) traverse(value, value.getClass());
    }
      }
    }
  }
  public static void main(String[] args) {
    ReferenceHandler rh = new ReferenceHandler();
    Object[] tab = new Object[4];
    tab[0] = new Point(1,1);     // Le tableau contient trois points,
    tab[1] = new Point(2,4);     // dont deux de mêmes coordonnées
    tab[2] = new Point(1,1);     // et son dernier élément est une
    tab[3] = tab;                // référence sur lui-même    
    rh.traverse(tab);
    Set s = rh.getHandlers();
    for (Iterator it = s.iterator(); it.hasNext(); ) {
      Map.Entry couple = (Map.Entry) it.next();
      System.out.println("objet: "+ couple.getKey() +
             " - handler: " + couple.getValue());
    }
  }
}