Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
GoslingJava2.doc
Скачиваний:
129
Добавлен:
23.02.2016
Размер:
2.39 Mб
Скачать

А.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 <<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();

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.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]