Java ME 上的 Class.getSuperclass() 替代品?

发布于 2024-08-19 06:18:28 字数 918 浏览 8 评论 0原文

如何获取 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);
   }
 }

How can I get the the superclass of a Class instance in Java ME. That is, fake the Class.getSuperclass() functionality with the limited functionality available in CLDC 1.1?

What I want to do is to let the abstract super class do something like this:

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 could then add specializations like this:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

烏雲後面有陽光 2024-08-26 06:18:28

正如您已经发现的,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

并将 AC 添加到树中并询问其超类C 的它会给你 A,如果你后来添加 B 它将取代 A 作为C,但直到为 C 的某些实例返回错误的样式器为止。

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

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

  • View 构造函数中,创建一个新的 Exception,但不要抛出它。
  • 暂时将 System.err 替换为您自己的编写器,写入 ByteArrayOutputStream
  • 在异常上调用 printStackTrace()
  • 恢复 System.err< /code> 为其原始值
  • 解析来自 ByteArrayOutputStream 的堆栈跟踪。中间类的构造函数的名称将出现在堆栈跟踪中。现在您可以使用 Class.forName() 查找它们并将它们添加到树中。

As you have already discovered, MIDP does not provide a method for getting the superclass of a class, nor for enumerating all classes in the application.

So all you can do is keep track of the class hierarchy yourself.

Having a common superclass makes it slightly easier, because you can have the new object add its own class to a global class collection (if not already present) in the superclass constructor:

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

but unfortunately this will not work for abstract classes, because no instances are ever created.

Keeping track of superclass/subclass relations for a known subset of classes is easy enough. e.g.:

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

But this can "miss" intermediate classes that are added later, e.g. if you have these classes:

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

and add A and C to the tree and asked it for the superclass of C it would give you A, and if you later added B it would replace A as the superclass of C, but not until the wrong styler had been returned for some instances of C.

So I think you will have to add the restriction that ancestor classes (that have stylers defined for them) must be added to the tree first. Possibly from the static initializer block of the class that overrides createStylerForViewClass, or the static initializer of the view class itself.

I did think of one other evil hack, but I can't really recommend it:

  • In the View constructor, create a new Exception, but don't throw it.
  • Temporarily swap System.err for your own writer that writes to a ByteArrayOutputStream
  • Call printStackTrace() on the exception
  • Restore System.err to its original value
  • Parse the stack trace from the ByteArrayOutputStream. The names of the intermediate classes' constructors will be in the stack trace. Now you can look them up using Class.forName() and add them to the tree.
心不设防 2024-08-26 06:18:28

您有两个选择:

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

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

 ClassA:SuperClass
 ClassB:AnotherSuperClass
 etc.

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

You have two options:

If you know that the super class belongs to a limited set, you can just call instanceof or use the Class.isInstance() method.

Alternatively, you can have a preprocessor to run on you code and create a data structure that is saved separately which holds your classes information. Probably even a custom doclet can do it. The output can be a text or binary file that describes the structure:

 ClassA:SuperClass
 ClassB:AnotherSuperClass
 etc.

Notice you may have problem with the obfuscation in this way.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文