Главная » Java » Вызов методов Java

0

из программ на C напоминает вызов конструкторов Java. Для этого используются следующие основные функции:

long *execute_java_static_method(ExecEnv *ee, ClassClass *cb, char *method_name, char *signature, …)

Выполняет статический метод класса, описываемого параметром cb.

long *execute_java_dynamic_method(ExecEnv *ee, HObject *obj, char *method_name, char *signature, …)

Выполняет нестатический (динамический) метод для заданного объекта.

В обоих функциях, параметр method_name является именем вызываемого метода, а signature описывает передаваемые аргументы. В отличие от конструкторов, вы также должны объявить возвращаемый методом тип после закрывающей скобки в сигнатуре. Возвращаемый тип указывается с использованием тех же сокращений, что и для типа параметров, с дополнительной буквой V для void. Примеры приведены ниже. Вы должны сами привести тип long к возвращаемому типу метода или проигнорировать  его для методов типа void.

Для получения структуры класса, используемой при вызове статических методов,

применяется одна из двух функций FindClass:

ClassClass *FindClass(ExecEnv *ee, char *class_name, bool_t resolve)

Возвращает указатель на структуру ClassClass для заданного класса. Как и прежде, параметр типа ExecEnv следует получить от функции EE. Логическая величина resolve аналогична одноименному параметру, используемому методом ClassLoader.loadClass в разделе 13.2.

ClassClass *FindClassFromClass(ExecEnv *ee, char *class_name, bool_t resolve, ClassClass

*from)

Возвращает указатель на объект-класс для заданного класса с использованием  объекта ClassLoader класса from.

Приведем пример, в котором метод System.out.println()  вызывается для вывода сведений о работе родного метода. Статический родной метод grindAway класса Crunch, приведенный ниже, осуществляет некоторые трудоемкие вычисления и возвращает результат типа double:

double

Crunch_grindAway(struct HCrunch *this_h)

{

ClassClass *myClass; HObject *out;

long i;

double result;

ExecEnv *ee = EE(); /* используется в нескольких местах */

myClass = FindClass(ee, "Crunch", TRUE);

out = (HObject *)execute_java_static_method(ee, myClass, "outStream", "()Ljava/io/PrintStream;");

if (exceptionOccurred(ee))

return 0.0;

for (i = 0; i << NUM_PASSES; i++) {

execute_java_dynamic_method(ee, out, "println", "(I)V", i);

if (exceptionOccurred(ee))

return 0.0;  // необходимо что-то вернуть

/* .. вычисления … */

}

return result;

}

Во фрагменте программы, предшествующем  циклу, мы получаем дескриптор объекта java.io.PrintStream  для System.out. Мы не можем непосредственно использовать значение статического поля System.out, потому что статические поля не имеют своего представления в родных методах; из-за этого приходится прибегать к обходным маневрам. В данном случае мы создаем статический метод, возвращающий нужное значение, и вызываем его из родного метода:

public static java.io.PrintStream outStream() {

return System.out;

}

Родной код должен получить указатель на структуру ClassClass для класса Crunch, поэтому мы вызываем FindClass. После этого можно вызвать функцию execute_java_static_method с указанием имени вызываемого метода и его сигнатуры, включающей тип возвращаемого значения. Мы преобразуем возвращаемое значение long к типу, необходимому для конкретного метода. В данном случае нам требуется общий дескриптор HObject, а не дескриптор для конкретного типа java.io.PrintStream.

После вызова метода проверяется, не было ли возбуждено исключение. Это стоит делать после каждого вызова метода или конструктора Java из родного кода, поскольку в противном случае вы можете пропустить исключение и иметь неприятности в будущем. Если мы выходим из функции по причине возникновения исключения, то возвращается фиктивное значение, которое игнорируется программой.

После того, как получен доступ к выходному потоку, можно начинать циклические вычисления. При проходе каждого цикла его номер выводится методом System.out.println. Для вызова этого метода мы используем функция execute_java_dynamic_method, передавая ей в качестве параметров объект, для которого вызывается метод, имя метода, его сигнатуру и аргументы. Нам нужна версия println, получающая аргумент типа int; этот метод имеет тип void, поэтому мы используем сигнатуру " (I)V" и передаем целое число, которое нужно вывести (i) после аргумента-сигнатуры. И снова при возврате из метода необходимо проверить, не возбуждено ли исключение.

Для многих типов, возвращаемых методами Java, приведение long к нужному типу происходит элементарно. Однако типы double и long в Java являются 64-разрядными, тогда как в большинстве существующих компиляторов C тип long 32-разрядный, и поэтому возвращаемое значение будет иметь только половинную длину. Хотя существуют

различные способы получения всех 64 бит возвращаемого значения, о них не говорится в этой книге из-за их машинной зависимости.

А.8 Последнее предупреждение

Мы должны снова предупредить вас о том, что конкретная схема стыковки, описанная здесь, в будущем обязательно изменится. Улучшения могут произойти как в плане реализации, так и на концептуальном уровне. Схема стыковки с C++ будет обладать другими характеристиками,  и, возможно, повлечет за собой изменения в схеме стыковки с C, сохраняя, однако, совместимость. Кроме того, создатели будущих сред разработки могут вообще отказаться от использования всех принципов, примененных в данной схеме. Мы надеемся, что в любом случае приведенный здесь материал поможет вам понять некоторые общие аспекты, возникающие при стыковке различных языков программирования,  и освоить схему связывания родных методов, которая будет использоваться  в вашей системе.

Источник: Арнольд К., Гослинг Д. – Язык программирования Java (1997)

По теме:

  • Комментарии