Доступ к функции через строку, хранящуюся в Hashtable

Если у меня есть имена функций, хранящиеся в виде строк в хеш-таблице.
Есть ли способ получить доступ к функциям через сохраненные строки?

РЕДАКТИРОВАТЬ Боюсь, платформа, над которой я работаю, CLDC1.1/MIDP2.0, не поддерживает Reflection.
Возможно ли какое-либо обходное решение?


person Kevin Boyd    schedule 06.09.2009    source источник


Ответы (5)


Просто используйте большой длинный список else-if:

[...]
} else if ("foo".equals(function)) {
    target. foo();
} else if ("bar".equals(function)) {
    target. bar();
[...]

(Хотя обычно я не люблю попытки вертикального выравнивания в исходном коде, я думаю, что в подобных случаях оно того стоит.)

Хранение функтора в карте является альтернативой, но это может слишком сильно увеличить размер объекта для многих приложений MIDP.

person Tom Hawtin - tackline    schedule 06.09.2009
comment
Мысль об этом делает меня благодарным за то, что я не разрабатываю JavaME, по крайней мере, на такой ограниченной платформе. - person Yishai; 06.09.2009
comment
@Tom: Вопрос о памяти имеет большой смысл! Что касается скорости, что было бы быстрее, чтобы найти метод HashTable или if/else-if. - person Kevin Boyd; 06.09.2009
comment
Вы могли бы подумать, что Hashtable будет быстрым для всех, кроме самого маленького n. Тем не менее, я думаю, что цепочка else-if должна работать достаточно быстро. (Это немного зависит от реализации. String.equals может использовать хэш, чтобы сразу отбросить почти все неравные строки.) - person Tom Hawtin - tackline; 06.09.2009

Class.forName() и newInstance() должны быть в MIDP 1.1 и могут быть полезны. Поскольку у вас нет полного отражения, вы можете создать класс, который обертывает все вызовы функций и вызывает их. Это предполагает, что вы знаете все вызовы функций заранее.

Вам понадобятся ссылки на все объекты, если только вы не выполняете статические вызовы. Немного сумбурно, но со своей задачей справится.

public Object invoke(String name, Object[] args) {
   Object f = functionMap.get(name);
   if("f1".equals(name)) {
       return ((SomeInterface1)f).someFunction1((SomeArg0) args[0]), ...);
   } else if ("f2".equals(name)) {
       return ((SomeInterface2)f).someFunction2((SomeArg0) args[0]), ...);
   }...{
   } else if ("fN".equals(name)) {
       return ((SomeInterfaceN)f).someFunctionN((SomeArg0) args[0]), ...);
   }
}
person Billy Bob Bain    schedule 06.09.2009

Учитывая имя функции, вы можете использовать отражение для доступа к методу. Помимо имени функции, вам нужно знать ее класс и иметь (или создать с помощью отражения, если у нее есть конструктор noarg или вы знаете, какие параметры передать конструктору) экземпляр (если метод не статический), и вы должны знать параметры, необходимые для перехода к нему.

Другой вариант — использовать класс Method в качестве указателя на функцию. Преимущество заключается в том, что он знает свой класс и знает свои требования к параметрам. У него есть недостаток, заключающийся в том, что он не сериализуем.

РЕДАКТИРОВАТЬ: нет способа получить доступ к методу в Java без отражения, просто имея его имя в виде строки. Если вам нужен альтернативный указатель на метод, вы можете использовать анонимный внутренний класс, который вызывает нужный вам метод, реализующий известный интерфейс, и передает его на карту. Это не подходит в качестве ключа карты, но будет работать как значение карты.

person Yishai    schedule 06.09.2009
comment
Есть ли другой способ? .. без использования отражения? - person Kevin Boyd; 06.09.2009

Я не пробовал отражение в javame, но в javase вы можете использовать отражение для динамического вызова метода.

Следующий фрагмент взят из: http://java.sun.com/developer/technicalArticles/ALT/Reflection/

import java.lang.reflect.*;

метод открытого класса2 { public int add (int a, int b) { return a + b; }

  public static void main(String args[])
  {
     try {
       Class cls = Class.forName("method2");
       Class partypes[] = new Class[2];
        partypes[0] = Integer.TYPE;
        partypes[1] = Integer.TYPE;
        Method meth = cls.getMethod(
          "add", partypes);
        method2 methobj = new method2();
        Object arglist[] = new Object[2];
        arglist[0] = new Integer(37);
        arglist[1] = new Integer(47);
        Object retobj 
          = meth.invoke(methobj, arglist);
        Integer retval = (Integer)retobj;
        System.out.println(retval.intValue());
     }
     catch (Throwable e) {
        System.err.println(e);
     }
  }

}

РЕДАКТИРОВАТЬ: Вместо того, чтобы использовать if..then..else, вы можете фактически передать число и использовать переключатель, так как его будет легче читать, IMO.

Но, несмотря на это, это, вероятно, ваш единственный вариант, учитывая ограничения JavaME.

person James Black    schedule 06.09.2009
comment
С помощью Java5, VarArgs и автоупаковки этот код можно значительно очистить. - person Yishai; 06.09.2009
comment
@ Кевин Бойд, я не знаю, как сделать это без размышлений, так как я даже не могу придумать, как сделать это с помощью АОП. Если вам нужна эта возможность, вы можете взглянуть на Groovy. Я подумаю об этом, пока буду в спортзале. ‹g› @Yishai, код можно почистить, я просто подумал, что может быть полезно показать какой-нибудь пример использования отражения, и я не верю, что JavaME поддерживает дженерики - person James Black; 06.09.2009

Я решаю подобные проблемы в Hecl, интерпретаторе, работающем на J2ME. Это зависит от того, с каким количеством строк вы хотите иметь дело, но один из работающих методов — это использовать хэш для поиска целого числа, а затем использовать его в операторе switch вместо большого списка операторов if/then. Кстати, вы можете использовать исходный код Hecl; он доступен под либеральной лицензией Apache.

person David N. Welton    schedule 07.09.2009
comment
Я вчера заглядывал в Hecl! Насколько сильны его возможности пользовательского интерфейса? - person Kevin Boyd; 07.09.2009
comment
Он может делать все, что может J2ME. Кто-то также предоставил порт MWT. Вы, вероятно, не хотите использовать его для работы с холстом, которая должна быть быстрой, как это интерпретируется, но для основных приложений это прекрасно! - person David N. Welton; 07.09.2009