Кен Арнольд Джеймс Гослинг
Вид материала | Документы |
- Джеймс трефил, 41001.36kb.
- Джеймс А. Дискретная математика и комбинаторика [Текст] / Джеймс А. Андерсон, 42.79kb.
- Человеческая способность эти ценности производить и использовать; является важнейшей, 110.76kb.
- Джеймс блиш города в полете 1-4 триумф времени вернись домой, землянин жизнь ради звезд, 10495.38kb.
- Джеймс Н. Фрей. Как написать гениальный роман, 2872.12kb.
- Дп «авто интернешнл» Київ, вул. Урицького, 1а Тел. (044) 20-60-333 Факс. (044) 20-60-343, 82.44kb.
- Тема Кол-во страниц, 26.85kb.
- Тема Кол-во страниц, 56.3kb.
- Тема Кол-во страниц, 20.7kb.
- Арнольд И. В. Стилистика современного английского языка, 20.42kb.
А.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, создается один дополнительный элемент, указывающий на объект класса, соответствующего типу элементов массива.
Приведем в качестве примера функцию, которая создает массив объектов заданного типа:
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 <
#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();
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):
static int
cmp(const void *str1, const void *str2)
{
return strcoll(*(char **)str1, *(char **)str2);
}
Функция сравнения cmp преобразует свои параметры-указатели к типу char ** (qsort требует, чтобы параметры имели тип void *; предполагается, что программист сам произведет все необходимые приведения типов). Затем вызывается стандартная библиотечная функция C с именем strcoll, которая сравнивает две строки с учетом локального контекста. Эта функция возвращает отрицательное, равное нулю или положительное число, если первая строка соответственно меньше, равна или больше второй в локальном языковом контексте упорядочения строк. То же самое функция qsort ожидает от своей функции сравнения, так что значение, возвращаемое strcoll, может возвращаться и самой функцией cmp.
После выполнения qsort, строки оказываются отсортированными в соответствии с функцией strcoll. Все, что остается — построить новый массив объектов String и заполнить его результатами. Далее, строится массив с помощью рассмотренной выше функции alloc_class_array и затем в цикле вызывается makeJavaString для задания каждого объекта String. Наконец, мы освобождаем массив strings, созданный функцией malloc, и возвращаем результат.
Упражнение А.6
Модифицируйте класс LocalString, чтобы он мог работать с объектами, каждый из которых обладает собственным локальным контекстом, вместо того, чтобы полагаться на один общий контекст. Методы перестанут быть статическими, и понадобится новое строковое поле, определяющее контекст. Помните, что функция POSIX с именем setlocale устанавливает локальный контекст лишь до следующего вызова setlocale.