3

Java ME でクラス インスタンスのスーパークラスを取得するにはどうすればよいですか。つまり、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

次の 2 つのオプションがあります。

スーパー クラスが限定されたセットに属していることがわかっている場合は、単に instanceof を呼び出すか、Class.isInstance()メソッドを使用できます。

または、コードで実行するプリプロセッサを用意し、クラス情報を保持する個別に保存されるデータ構造を作成することもできます。おそらく、カスタムドックレットでさえそれを行うことができます。出力は、構造を説明するテキスト ファイルまたはバイナリ ファイルにすることができます。

 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とをCツリーに追加し、 のスーパークラスを要求CするAと、後で追加するとのスーパークラスとしてB置き換えられますが、 のいくつかのインスタンスに対して間違ったスタイラーが返されるまではそうではありません。ACC

したがって、祖先クラス (スタイラーが定義されている) を最初にツリーに追加する必要があるという制限を追加する必要があると思います。おそらく、オーバーライドするクラスの静的初期化子ブロックcreateStylerForViewClass、またはビュー クラス自体の静的初期化子からです。

私は別の邪悪なハックを考えましたが、あまりお勧めできません:

  • Viewコンストラクターで、新しい を作成しますが、Exceptionスローしないでください。
  • System.errに書き込む独自のライターと一時的に交換します。ByteArrayOutputStream
  • printStackTrace()例外を呼び出す
  • System.err元の値に戻す
  • からスタック トレースを解析しますByteArrayOutputStream。中間クラスのコンストラクターの名前は、スタック トレースに表示されます。これで、 を使用して検索しClass.forName()、ツリーに追加できます。
于 2010-01-31T13:52:02.867 に答える