Class.getSuperclass () en reemplazo de Java ME?
Pregunta
¿Cómo puedo conseguir el la superclase de una instancia de clase en Java ME. Es decir, la funcionalidad falsa Class.getSuperclass () con la funcionalidad limitada disponible en CLDC 1.1?
Lo que quiero hacer es dejar que la superclase abstracta hacer algo como esto:
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;
}
}
clases Sub entonces podría añadir especializaciones como esto:
public Styler createStylerForViewClass(Class clazz) {
if (clazz == SpecialView.class) {
return new SpecialStyler();
} else {
return super.createSylerForViewClass(clazz);
}
}
Solución
Como ya se ha descubierto, MIDP no proporciona un método para conseguir la superclase de una clase, ni para enumerar todas las clases de la aplicación.
Así que todo lo que puede hacer es no perder de vista la jerarquía de clases usted mismo.
Tener una superclase común hace que sea un poco más fácil, ya que se puede tener el nuevo objeto de añadir su propia clase a una colección de clase mundial (si no está ya presente) en el constructor de la superclase:
abstract class View {
protected View() {
classHierarchy.add(this.getClass());
}
}
pero por desgracia esto no funcionará para las clases abstractas, porque no hay casos se han creado.
Hacer un seguimiento de las relaciones superclase / subclase para un subconjunto conocido de clases es bastante fácil. por ejemplo:.
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;
}
Sin embargo, esto puede "miss" clases intermedias que se agregan más tarde, por ejemplo, Si usted tiene estas clases:
Object >= View >= A >= B >= C
y A
complemento y C
al árbol y se les pidió que para la superclase de C
que le daría A
, y si después se agregaban B
que reemplazaría A
como la superclase de C
, pero no hasta que había sido devuelto el moldeador mal para algunos casos de C
.
Así que creo que tendrá que añadir la restricción de que los ancestros clases (que tienen stylers definidos para ellos) deben ser añadidos al árbol en primer lugar. Posiblemente de la estática inicializador bloque de la clase que anula createStylerForViewClass
, o la estática inicializador de la propia clase de vista.
Me hizo pensar en otro truco mal, pero no puedo realmente recomiendo:
- En el constructor
View
, crear un nuevoException
, pero no lo tire. - Temporalmente
System.err
de intercambio para su propio escritor que escribe en unByteArrayOutputStream
-
printStackTrace()
llamada en la excepción - Restaurar
System.err
a su valor original - Analizar el seguimiento de pila de la
ByteArrayOutputStream
. Los nombres de los constructores de las clases intermedias estarán en el seguimiento de la pila. Ahora se puede mirar hacia arriba usandoClass.forName()
y añadirlos al árbol.
Otros consejos
Existen dos opciones:
Si sabe que la super clase pertenece a un grupo limitado, sólo puede llamar a instanceof o utilizar el Class.isInstance () método.
Como alternativa, puede tener un preprocesador para funcionar con su código y crear una estructura de datos que se guarda por separado que contiene la información de clases. Probablemente incluso una costumbre doclet lata hazlo. La salida puede ser un texto o un archivo binario que describe la estructura:
ClassA:SuperClass
ClassB:AnotherSuperClass
etc.
Aviso que puede tener un problema con la ofuscación de esta manera.