2010-01-20 20 views
3

Comment puis-je obtenir la super-classe d'une instance de classe dans Java ME. C'est-à-dire, fausse la fonctionnalité Class.getSuperclass() avec la fonctionnalité limitée disponible dans CLDC 1.1?Remplacement Class.getSuperclass() sur Java ME?

Ce que je veux faire est de laisser la classe abstraite super faire quelque chose comme ceci:

public Styler getStylerForViewClass(Class clazz) { 
    Styler s = stylers.get(clazz); 
    if (s == null) { 
    for (Class c = clazz; s == null; c = c.getSuperclass()) { 
     if (c == Object.class) { 
     throw new IllegalArgumentException("No Styler for " + clazz.getName()); 
     } 
     s = createStylerForViewClass(c); 
    } 
    stylers.put(clazz, s); 
    } 
    return s; 
} 
public Styler createStylerForViewClass(Clazz clazz) { 
    if (clazz == View.class) { 
    return new DefaultStyler(); 
    } else { 
    return null; 
    } 
} 

sous-classes pourraient alors ajouter des spécialisations comme ceci:

public Styler createStylerForViewClass(Class clazz) { 
    if (clazz == SpecialView.class) { 
    return new SpecialStyler(); 
    } else { 
    return super.createSylerForViewClass(clazz); 
    } 
} 
+0

Existe-t-il une super-classe commune à toutes les classes d'affichage? Et ces méthodes ('createStylerForViewClass' et' getStylerForViewClass') appartiennent-elles à cette superclasse? Si oui, pourquoi le paramètre 'clazz' est-il requis? – finnw

+0

Oui, ils ont une super-classe commune, mais vous ne mettra pas en œuvre ces méthodes. Appelez simplement getStylerForViewClass() avec leur propre classe afin d'obtenir le style le plus approprié pour eux. – PeyloW

Répondre

1

Comme vous l'avez déjà découvert, MIDP ne fournit pas de méthode pour obtenir la super-classe d'une classe, ni pour énumérer toutes les classes de l'application.

Donc tout ce que vous pouvez faire est de garder une trace de la hiérarchie des classes vous-même.

Avoir une superclasse commune rend un peu plus facile, parce que vous pouvez avoir le nouvel objet ajouter sa propre classe à une collection de classe mondiale (si pas déjà) dans le constructeur superclasse:

abstract class View { 
    protected View() { 
     classHierarchy.add(this.getClass()); 
    } 
} 

, mais malheureusement, ce ne fonctionnera pas pour les classes abstraites, car aucune instance n'est créée.

Garder la trace des relations superclasse/sous-classe pour un sous-ensemble connu de classes est assez facile. .: par exemple

import java.util.Enumeration; 
import java.util.Hashtable; 
import java.util.Vector; 

public class ClassHierarchy { 
public ClassHierarchy() { 
    childToParentMap = new Hashtable(); 
    parentToChildMap = new Hashtable(); 
    parentToChildMap.put(Object.class, new Vector()); 
} 

public boolean addClass(Class toAdd) { 
    if (toAdd.isInterface()) return false; 
    if (toAdd.equals(Object.class)) return false; 
    if (childToParentMap.get(toAdd) != null) return false; 

    addClassBelow(toAdd, Object.class, new Vector()); 
    return true; 
} 

public Class getParent(Class subclass) { 
    return (Class) childToParentMap.get(subclass); 
} 

private void addClassBelow(Class toAdd, Class parent, Vector initialChildren) { 
    Vector children = (Vector) parentToChildMap.get(parent); 
    Class reparented; 
    do { 
    reparented = null; 
    for (Enumeration childEnum = children.elements(); 
     childEnum.hasMoreElements(); 
     ) { 
    Class child = (Class) childEnum.nextElement(); 
    if (child.isAssignableFrom(toAdd)) { 
    addClassBelow(toAdd, child, initialChildren); 
    return; 
    } else if (toAdd.isAssignableFrom(child)) { 
    children.removeElement(child); 
    initialChildren.addElement(child); 
    childToParentMap.put(child, toAdd); 
    // Guard against concurrent modification 
    reparented = child; 
    break; 
    } 
    } 
    } while (reparented != null); 

    children.addElement(toAdd); 
    childToParentMap.put(toAdd, parent); 
    parentToChildMap.put(toAdd, initialChildren); 
} 


private Hashtable childToParentMap; 

private Hashtable parentToChildMap; 
} 

Mais cela peut « manquer » les classes intermédiaires qui sont ajoutés plus tard, par exemple si vous avez ces classes:

Object >= View >= A >= B >= C 

et ajouter A et C à l'arbre et lui a demandé pour la superclasse de C il vous donnera A, et si vous avez ajouté plus tard B il remplacerait A comme superclasse de C , mais pas avant que le mauvais styler ait été retourné pour certaines instances de C.

Donc je pense que vous devrez ajouter la restriction que les classes d'ancêtres (qui ont des stylers définis pour eux) doivent être ajoutées à l'arbre en premier. Peut-être à partir du bloc d'initialisation statique de la classe qui remplace createStylerForViewClass ou l'initialiseur statique de la classe de vue elle-même.

Je ne pensais d'un autre bidouille mal, mais je ne peux pas recommander vraiment:

  • Dans le constructeur View, créez un nouveau Exception, mais ne le jetez pas.
  • temporairement permuter System.err pour votre propre écrivain qui écrit à un ByteArrayOutputStream
  • Appel printStackTrace() à l'exception
  • Restore System.err à sa valeur initiale
  • Parse la trace de la pile de la ByteArrayOutputStream. Les noms des constructeurs des classes intermédiaires seront dans la trace de la pile. Maintenant, vous pouvez les rechercher en utilisant Class.forName() et les ajouter à l'arbre.
+0

Assez bon pour travailler avec. Je pense que j'aurai besoin de toutes les sous-classes de View pour appeler 'registerClass (MyClass.class)' en tant qu'initialisateur statique. Difficile à appliquer, mais assez bon. Le vilain hack de vôtre n'est pas faisable, puisque 'System.err' si' final' en CLDC, j'ai déjà envisagé ceci :(. – PeyloW

+0

Aucun moyen standard pour obtenir une trace de pile dans J2ME. émulateur ou utiliser un téléphone Symbian et son protocole GCF "redirect: //". –

1

Vous avez deux options:

Si vous savez que la super classe appartient à un ensemble limité, vous pouvez simplement appeler instanceof ou utiliser la méthode Class.isInstance(). Vous pouvez également avoir un préprocesseur à exécuter sur votre code et créer une structure de données qui est enregistrée séparément qui contient vos informations de classes. Probablement même une coutume doclet peut le faire. La sortie peut être un texte ou d'un fichier binaire qui décrit la structure:

ClassA:SuperClass 
ClassB:AnotherSuperClass 
etc. 

avis vous pouvez avoir des problèmes avec l'obscurcissement de cette façon.

+0

Personnellement, j'essaierais de m'en tenir à l'opérateur 'instanceof' et d'essayer d'utiliser un ensemble limité de classes. Je n'aime pas vraiment utiliser les préprocesseurs car ils peuvent rendre votre code plus obscur. – Malcolm

+0

Je n'avais pas l'intention d'utiliser le préprocesseur pour manipuler le texte. Voir la réponse pour clarification. –

+0

Je ne peux pas savoir ce que les superclasses peuvent être, puisque je suis la mise en œuvre du cadre. Je n'ai aucun contrôle sur les styles que les clients souhaitent utiliser. Je veux juste créer une méthode de chargement flexible et paresseux pour aller chercher le styler correct pour n'importe quelle classe donnée. – PeyloW