Java JNI: столкновение глобальной переменной в нативном коде - PullRequest
2 голосов
/ 02 марта 2010

Добрый день, мастера. Предположим, у меня есть класс Java:

class A {
    public A() {}
    public native void setValue(String value);
    public native String getValue();
}

При реализации нативного кода C глобальная переменная char [] используется для хранения значения, которое просто устанавливается нативным методом setValue. Метод getValue просто возвращает эту глобальную переменную char [].

Здесь возникает мой вопрос: я создаю несколько объектов A и вызываю их соответствующий метод set / get, я обнаружил, что в итоге они записывают и читают один и тот же блок памяти! На самом деле глобальная переменная char [] в собственном коде C полностью используется всеми объектами A.

Кто-нибудь может дать мне подробное объяснение этого поведения? Я знал, что у меня было фундаментальное недоразумение с точки зрения работы JNI. Спасибо!

1 Ответ

7 голосов
/ 02 марта 2010

Проблема в том, что у вас есть объектно-ориентированный Java с одной стороны, а процедурный C - с другой. Когда загружается Java-класс A, JNI каким-то образом не создает объект в мире C (это C - не C ++), нет сопоставления объекта с объектом. Поэтому JNI загружает соответствующий файл CPP в мире C один раз в память (это совершенно нормальное поведение в C). Компилятор видит кучу функций и глобальную ссылку, поэтому нет необходимости создавать несколько экземпляров. При загрузке Java-класса все, что делает JNI-компилятор, - это добавляет файл C в список файлов для компиляции.

То, что вы хотели бы иметь, - это отображение между объектами Java и объектами C. Это может быть достигнуто несколькими способами, я предлагаю вам прочитать о шаблоне прокси в JNI.

Чтобы объяснить очень коротко, у вас есть два основных способа добиться этого. Вы можете сделать это на стороне C или на стороне Java. При хранении отношений в мире C вы должны поддерживать хеш-таблицу в C, где объекты C отображаются на объекты Java. С другой стороны, у вас будет объект int в Java-объекте, который фактически является указателем на объект C в памяти. В коде C вы можете разыменовать этот указатель (через GetIntField ()) и привести к нужному вам объекту C.

Конечно, добавив

private String value;

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

env->GetObjectField(obj, "value", "Ljava/lang/String;")

, а env - среда JNI.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...