3

如何在 Java ME 中获取 Class 实例的超类。也就是说,使用 CLDC 1.1 中可用的有限功能来伪造 Class.getSuperclass() 功能?

我想做的是让抽象超类做这样的事情:

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;
  }
}

然后子类可以添加这样的专业化:

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

2 回答 2

1

你有两个选择:

如果您知道超类属于有限集,您可以调用 instanceof 或使用Class.isInstance()方法。

或者,您可以让预处理器在您的代码上运行并创建一个单独保存的数据结构,以保存您的类信息。可能甚至自定义doclet也可以做到。输出可以是描述结构的文本或二进制文件:

 ClassA:SuperClass
 ClassB:AnotherSuperClass
 etc.

请注意,您可能会遇到这种混淆的问题。

于 2010-01-20T19:57:02.017 回答
1

正如您已经发现的那样,MIDP 不提供获取类的超类的方法,也不提供枚举应用程序中所有类的方法。

因此,您所能做的就是自己跟踪类层次结构。

拥有一个通用的超类会稍微容易一些,因为您可以让新对象将其自己的类添加到超类构造函数中的全局类集合(如果尚未存在)中:

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

但不幸的是,这不适用于抽象类,因为从未创建任何实例。

跟踪已知类子集的超类/子类关系很容易。例如:

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;
}

但这可能会“错过”稍后添加的中间类,例如,如果您有这些类:

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

A并将and添加C到树中并询问它C会给你的超类A,如果你以后添加B它,它将替换A为 的超类C,但直到为某些实例返回错误的样式器C

因此,我认为您将必须添加必须首先将祖先类(为其定义了样式器)添加到树中的限制。可能来自覆盖的类的静态初始化程序块createStylerForViewClass,或视图类本身的静态初始化程序。

我确实想到了另一个邪恶的黑客,但我不能真正推荐它:

  • View构造函数中,创建一个 new Exception,但不要抛出它。
  • 暂时换成System.err你自己的作家来写ByteArrayOutputStream
  • 调用printStackTrace()异常
  • 恢复System.err到原来的价值
  • ByteArrayOutputStream. 中间类的构造函数的名称将在堆栈跟踪中。现在您可以使用它们查找它们Class.forName()并将它们添加到树中。
于 2010-01-31T13:52:02.867 回答