Class.getsuperclass () substituição em java me?
Pergunta
Como posso obter a superclasse de uma instância de classe em Java Me. Isto é, falsificar a funcionalidade da classe.getSuperclass () com a funcionalidade limitada disponível no CLDC 1.1?
O que eu quero fazer é deixar a super classe abstrata fazer algo assim:
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;
}
}
Sub -classes podem então adicionar especializações como esta:
public Styler createStylerForViewClass(Class clazz) {
if (clazz == SpecialView.class) {
return new SpecialStyler();
} else {
return super.createSylerForViewClass(clazz);
}
}
Solução
Como você já descobriu, o MIDP não fornece um método para obter a superclasse de uma classe, nem para enumerar todas as classes no aplicativo.
Então, tudo o que você pode fazer é acompanhar a hierarquia da classe.
Ter uma superclasse comum facilita um pouco, porque você pode ter o novo objeto adicionar sua própria classe a uma coleção de classes globais (se ainda não estiver presente) no construtor de superclasse:
abstract class View {
protected View() {
classHierarchy.add(this.getClass());
}
}
Infelizmente, porém, isso não funcionará para classes abstratas, porque nenhuma instância foi criada.
Manter o controle das relações de superclasse/subclasse para um subconjunto de classes conhecido é fácil o suficiente. por exemplo:
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;
}
Mas isso pode "perder" classes intermediárias que são adicionadas posteriormente, por exemplo, se você tiver essas aulas:
Object >= View >= A >= B >= C
e adicione A
e C
para a árvore e pediu a superclasse de C
Isso te daria A
, e se você adicionou mais tarde B
substituiria A
como a superclasse de C
, mas não até que o estilador errado tenha sido devolvido por alguns casos de C
.
Então, acho que você terá que acrescentar a restrição de que as classes de ancestrais (que tenham estilistas definidas para eles) devem ser adicionadas primeiro à árvore. Possivelmente do bloco inicializador estático da classe que substitui createStylerForViewClass
, ou o inicializador estático da própria classe de exibição.
Eu pensei em outro hack do mal, mas não posso recomendar:
- No
View
construtor, crie um novoException
, mas não jogue. - Troque temporariamente
System.err
Para seu próprio escritor que escreve para umByteArrayOutputStream
- Ligar
printStackTrace()
na exceção - Restaurar
System.err
ao seu valor original - Analisar o rastreamento da pilha do
ByteArrayOutputStream
. Os nomes dos construtores das classes intermediárias estarão no rastreamento da pilha. Agora você pode procurá -los usandoClass.forName()
e adicione -os à árvore.
Outras dicas
Você tem duas opções:
Se você sabe que a super classe pertence a um conjunto limitado, você pode apenas ligar para a instância ou usar o Class.isInsinStance () método.
Como alternativa, você pode ter um pré -processador para executar seu código e criar uma estrutura de dados salva separadamente, que mantém as informações das classes. Provavelmente até um costume Doclet pode fazer isso. A saída pode ser um texto ou arquivo binário que descreve a estrutura:
ClassA:SuperClass
ClassB:AnotherSuperClass
etc.
Observe que você pode ter problemas com a ofuscação dessa maneira.