Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Язык программирования JAVA.pdf
Скачиваний:
373
Добавлен:
02.05.2014
Размер:
2.57 Mб
Скачать

converted to PDF by BoJIoc

}

static int setup_lock(

struct flock *lock, long mode)

{

lock->>l_whence = lock->>l_start = lock->>l_len = 0; switch (mode) {

case local_LockableFile_READ: lock->>l_type = F_RDLCK; break;

case local_LockableFile_WRITE: lock->>l_type = F_WRLCK; break;

default:

SignalError(EE(), "java/lang/IllegalArgumentException", NULL);

return 0;

}

return 1;

}

А.4 Строки

Родные методы часто должны использовать строковые объекты String. Заголовочный файл <<javaString.h>> определяет несколько функций, помогающих в решении этой задачи. Все функции, преобразующие объекты String языка Java в строки C, переносят в них только младшие 8 бит символов Unicode. Эти функции работают с дескрипторами, которые передаются родным методам, хранятся в структурах языка C или создаются с помощью приведенных ниже функций.

char *allocCString(Hjava_lang_String *str)

Вызывает функцию malloc языка C для создания буфера, размер которого достаточен для хранения строки. Когда вы закончите работать со строкой, не забудьте вызвать free для возвращенного указателя.

char *javaString2CString(Hjava_lang_String *str, char buffer[], int length)

Копирует до length символов из str в buffer. Размещение и освобождение буфера лежит на совести программиста. Для удобства функция возвращает buffer.

char *makeCString(Hjava_lang_String *str)

Возвращает строку языка C, которая может быть уничтожена сборщиком мусора. Сборщик мусора в поисках ссылок сканирует не только объекты Java, но и данные C, поэтому строка не может быть уничтожена им в случае, если указатель на нее используется в родном методе.

int javaStringLength(Hjava_lang_String *str)

Возвращает длину строки Java. Функции передается параметр-дескриптор.

unicode *javaString2unicode(Hjava_lang_String *str, unicode *buf, int len)

converted to PDF by BoJIoc

Копирует до len символов Unicode из str в буфер buf. Тип данных unicode определяется при включении файла <<native.h>> и представляет собой 16-разрядное символьное значение.

Для создания новых объектов используется функция makeJavaString:

Hjava_lang_String *makeJavaString(char *str, int len)

Возвращает дескриптор нового строкового объекта, созданного на основе строки str языка C, с использованием начальных len байтов строки. Длина не должна учитывать нуль-байт, завершающий строку в языке C.

Если какой-либо из этих методов столкнется с ошибкой (например, нехваткой памяти), он вызывает SignalError с соответствующим исключением и возвращает NULL. В этом случае необходимо выполнить нужные завершающие действия и выйти из функции.

Ниже показано, как можно написать родной метод с использованием функции strxfrm, соответствующей стандарту ANSI C, которая по обычной 8-разрядной строке стандарта Latin-1 создает порядковую строку, соответствующую локальному языковому контексту.

Созданная строка может использоваться для сравнения исходной строки с другими строками. Локальный языковой контекст определяет порядок сортировки принятый во французском языке, норвежском, испанском и т. д. Сортировка строк с помощью функции strxfrm выполняется следующим образом:

1.Вызовите strxfrm для двух строк, чтобы создать для каждой из них порядковую строку.

1.Сравните порядковые строки функцией strcmp, которая возвращает отрицательное, равное нулю или положительное число, если первая строка соответственно меньше, равна или больше второй.

1.Упорядочите исходные строки в зависимости от результатов вызова strcmp для двух порядковых строк.

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

Приведем пример класса, который содержит вспомогательные методы, учитывающие особенности языков при работе со строками:

package local;

public class LocalString {

/** возвращает порядковую строку для str */ public native static String xfrm(String str);

/** сортирует массив в соответствии с локальным контекстом */ public native static String[] sort(String[] input);

static { System.loadLibrary("LocalString");

}

}

Метод sort мы рассмотрим в следующем разделе. Вот один из способов реализации xfrm: HString *

local_LocalString_xfrm(

converted to PDF by BoJIoc

struct Hlocal_LocalString *this_h, Hjava_lang_String *str_h)

{

Hjava_lang_String *retval; char *str, *xfrm;

size_t xfrm_len;

set_locale();

str = allocString(str_h); if (str == Null)

return NULL; /* функция allocString() вызвала SignalError */ xfrm_len = strxfrm(Null, str, 0);

if ((xfrm = (char *)malloc(xfrm_len + 1)) == NULL) { SignalError(EE(),

"java/lang/OutOfMemorytException", NULL); return NULL;

}

strxfrm(xfrm, str, xfrm_len);

retval = makeJavaString(xfrm, xfrm_len); free(xfrm);

free(str); return retval;

}

Первое, что мы должны сделать - это настроить локальный контекст функцией set_locale:

#include <<locale.l>>

void set_locale()

{

static int done_set = 0;

if (!done_set) { setlocale(LC_COLLATE, ""); done_set++;

}

}

Функция setlocale устанавливает алгоритм сравнения строк для локального контекста, заданного переменными среды, на что указывает параметр "". После выхода из set_locale мы выделяем место под новую строку языка C, содержимое которой совпадает с содержимым передаваемого параметра, и проверяем возможные ошибки. Далее мы используем вариант функции strxfrm, который возвращает количество символов для порядковой строки, выделяем буфер, рассчитанный на данное количество символов плюс один символ для нуль-байта, и заполняем буфер функцией strxfrm. Затем мы вызываем makeJavaString, чтобы создать новый объект String, содержащий порядковую строку. Перед тем, как возвращать ее, необходимо освободить выделенную память. Наконец, мы возвращаем объект String, содержащий порядковую строку.

Ничто не может помешать программе на C модифицировать символы в структуре Classjava_lang_String, соответствующей объекту String языка Java. Тем не менее, это нарушает гарантию того, что объекты String доступны только для чтения, на которую часто полагаются runtime-система Java, сгенерированный программный код и классы. Например, два объекта String с одинаковым содержимым часто могут совместно использовать одну и ту же область памяти. Модификация одного объекта String не только нарушает гарантию она может привести к одновременной модификации других объектов String.

Упражнение А.3

converted to PDF by BoJIoc

Напишите родной метод, который выводит содержимое объекта String.

Упражнение А.4

Напишите родной метод, который возвращает системную строку, недоступную классам Java — например, имя текущего рабочего каталога или папки.

Упражнение А.5

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

А.5 Массивы

Массивы в Java являются типизированными они могут состоять из значений примитивного типа (массив int) или из объектов класса. Тип массива Java учитывается при его переводе в C. Существуют специальные типы массивов для примитивных значений и универсальный тип для массивов, содержащих объекты. Каждый массив в языке C представлен структурой следующего вида:

typedef struct { CType *body;

} ArrayOfJavaType;

В каждой структуре имеется поле с именем body, указывающее на элементы массива; CType тип языка C, которому соответствует тип элементов массива, а JavaType имя типа в языке Java. В таблице показано, как происходит перевод различных массивов из

Java в C:

Тип массива в Java Имя структуры Тип body Тип размещаемого массива в C

boolean

ArrayOfInt

long

 

T_BOOLEAN

 

 

 

 

 

 

 

 

 

 

byte

ArrayOfByte

char

 

T_BYTE

 

 

 

 

 

 

 

 

 

 

short

ArrayOfShort

short

 

T_SHORT

 

 

 

 

 

 

 

 

 

 

int

ArrayOfInt

long

 

T_INT

 

 

 

 

 

 

 

 

 

 

long

ArrayOfLong

int64_t

 

T_LONG

 

 

 

 

 

 

 

 

 

 

float

ArrayOfFloat

float

 

T_FLOAT

 

 

 

 

 

 

 

 

 

 

double

ArrayOfDouble

double

 

T_DOUBLE

 

 

 

 

 

 

 

 

 

 

char

ArrayOfChar

unicode

 

T_CHAR

 

 

 

 

 

 

 

 

 

 

Object

ArrayOfObject

Hobject

 

T_CLASS

 

 

 

 

 

Доступ к элементам массива осуществляется стандартным образом, в виде body[i]; максимальный индекс на единицу меньше количества элементов в массиве. Функция obj_Length возвращает количество элементов в заданном массиве.

Для создания массива используется функция ArrayAlloc:

Handle *ArrayAlloc(int type, int size)

Создает новый массив заданного типа type, который должен быть одним из типов в приведенной выше таблице. Если параметр type равен T_CLASS,

converted to PDF by BoJIoc

создается один дополнительный элемент, указывающий на объект класса, соответствующего типу элементов массива.

Приведем в качестве примера функцию, которая создает массив объектов заданного типа:

HArrayOfObject * alloc_class_array(

char *type, int cnt)

{

HArrayOfObject *retval;

retval = (HArrayOfObject *)ArrayAlloc(T_CLASS, cnt); if (retval == NULL) {

SignalError(EE(), "java/lang/OutOfMemorytException", NULL);

return NULL;

}

unhand(retval)->>body[cnt] =

(HObject *)FindClass(EE(), type, TRUE); return retval;

}

Сначала мы пытаемся создать массив типа T_CLASS и проверяем, удалось ли нам это. Затем - получаем объект Class для заданного типа. Функция FindClass получает в качестве параметров среду выполнения, имя типа в виде строки языка C и логическое значение, которое определяет необходимость загрузки класса в том случае, если он не был ранее загружен. Функция EE возвращает текущее состояние среды выполнения.

Объект, возвращаемый функцией FindClass, вставляется после конца массива и используется runtime-системой для проверки того, что каждый заносимый в массив элемент относится к правильному типу. Чтобы создать массив, который может содержать любые объекты, следует воспользоваться классом "java/lang/Object".

Реализация LocalString.sort показывает, как работает вся эта инфраструктура. Сначала давайте посмотрим, как реализована сама функция local_LocalString_sort:

#include "local_LocalString.h" #include <<stdlib.h>> #include ,javaString.h>>

HArrayOfString * local_LocalString_sort(

struct Hlocal_LocalString *this_h, HArrayOfString *strngs_h)

{

ClassArrayOfString *in_strings; HArrayOfString *retval = NULL; ClassArrayOfString *retstrs; char **string = NULL;

int i, str_cnt;

if (strings_h ==NULL) { /* проверить ссылку */ SignalError(EE(),

"java/lang/NullPointerException", "null array"); return NULL;

}

set_locale();

converted to PDF by BoJIoc

in_strings = unhand(strings_h); str_cnt = obj_length(strings_h);

strings = (char **)malloc(str_cnt * sizeof *strings); if (strings == NULL) {

SignalError(EE(), "java/lang/OutOfMemorytException", NULL);

return NULL;

}

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

if (in_strings->>body[i] == NULL) { SignalError(EE(), "java/lang/NullPointerException", "Null string in array");

goto cleanup;

}

strings[i] = makeCString(in_strings->>body[i]); if (strings[i] == NULL)

goto cleanup; /* функция SignalError() уже вызвана */

}

qsort(strings, str_cnt, sizeof *strings, cmp); retval = (HArrayOfString *)

alloc_class_array("java/lang/String", str_cnt); retstrs = unhand(retval);

for (i = 0; i << str_cnt; i++) { retstrs->>body[i] =

makeJavaString(strings[i], strlen(strings[i]));

}

cleanup:

free(strings); return retval;

}

Сначала мы проверяем, действительно ли был передан массив. Затем устанавливается локальный контекст, как это делалось в LocalString.xfrm.

Затем создаем строковый массив, в котором будет храниться содержимое сортируемых объектов String. Для создания строкового массива необходимо знать, сколько строк в него входит это число получается вызовом obj_length для дескриптора строкового массива.

Затем мы используем функцию malloc для выделения памяти под указатели и проверяем возвращаемое ею значение.

Проверка ошибок чрезвычайно важна. Родные методы, не анализирующие возможные ошибки, нарушают те гарантии безопасности, которые Java предоставляет программистам. Например, если бы мы пропустили проверку равенства ссылки null, то

при попытке использования этого указателя вместо возбуждения исключения NullPointerException все бы кончилось крахом программного потока, а возможно и всего приложения.

Получив место для хранения строк языка C, мы в цикле перебираем элементы входного массива и сохраняем копии исходных строк в массиве сортировки. При этом мы не забываем проверять наличие null-ссылок среди этих элементов. В нашей функции была использована функция makeCString главным образом для того, чтобы показать, как ей пользоваться. Кроме того, это упрощает программу, поскольку сборщик мусора будет сам уничтожать все возвращаемые строки, в том числе и при возникновении ошибок.

Теперь массив strings содержит эквиваленты исходных строк в языке C. Мы вызываем стандартную библиотечную функцию C с именем qsort, чтобы отсортировать массив, и передаем ей в качестве последнего аргумента функцию (в данном случае cmp):