Вопрос

Как я могу получить суперкласс экземпляра класса в Java ME.То есть подделать функциональность Class.getSuperclass() с ограниченной функциональностью, доступной в CLDC 1.1?

Что я хочу сделать, так это позволить абстрактному суперклассу делать что-то вроде этого:

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);
   }
 }
Это было полезно?

Решение

Как вы уже обнаружили, 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 это заменило бы A как суперкласс C, но только до тех пор , пока не был возвращен неправильный стилизатор для некоторых экземпляров C.

Поэтому я думаю, вам придется добавить ограничение, согласно которому классы-предки (для которых определены стилеры) должны быть сначала добавлены в дерево.Возможно, из блока статического инициализатора класса, который переопределяет createStylerForViewClass, или статический инициализатор самого класса view.

Я действительно думал об одном другом злом взломе, но я не могу действительно рекомендовать его:

  • В View конструктор, создайте новый Exception, но не бросайте его.
  • Временно поменяться местами System.err для вашего собственного автора, который пишет в ByteArrayOutputStream
  • Позвонить printStackTrace() об исключении
  • Восстановить System.err к своему первоначальному значению
  • Проанализируйте трассировку стека из ByteArrayOutputStream.Имена конструкторов промежуточных классов будут указаны в трассировке стека.Теперь вы можете просмотреть их с помощью Class.forName() и добавьте их в дерево.

Другие советы

У вас есть два варианта:

Если вы знаете, что суперкласс принадлежит к ограниченному набору, вы можете просто вызвать instanceof или использовать Класс.isInstance() способ.

В качестве альтернативы, вы можете использовать препроцессор для запуска вашего кода и создания структуры данных, которая сохраняется отдельно и содержит информацию о ваших классах.Возможно, даже обычай доклет могу это сделать.Результатом может быть текстовый или двоичный файл, описывающий структуру:

 ClassA:SuperClass
 ClassB:AnotherSuperClass
 etc.

Обратите внимание, что у вас могут возникнуть проблемы с запутыванием таким образом.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top