Подключение внешних библиотек dll.“Родные” (native) методы*
*- данный параграф приводится в ознакомительных целях
Для прикладного программирования средств Java в подавляющем большинстве случаев хватает. Однако иногда возникает необходимость подключить к программе ряд системных вызовов. Либо обеспечить доступ к библиотекам, написанным на других языках программирования. Для таких целей в Java используются методы, объявленные с модификатором native –“родной”. Это слово означает, что при выполнении метода производится вызов “родного” для конкретной платформы двоичного кода, а не платформо-независимого байт-кода как во всех других случаях. Заголовок “родного” метода описывается в классе Java, а его реализация осуществляется на каком-либо из языков программирования, позволяющих создавать динамически подключаемые библиотеки (DLL – Dynamic Link Library под Windows, Shared Objects под UNIX-образными операционными системами).
Правило для объявления и реализации таких методов носит название JNI – Java Native Interface.
Объявление “родного” метода в Java имеет вид
Модификаторы native ВозвращаемыйТип имяМетода(список параметров);
Тело “родного” метода не задаётся – оно является внешним и загружается в память компьютера с помощью загрузки той библиотеки, из которой этот метод должен вызываться:
System.loadLibrary(“ИмяБиблиотеки”);
При этом имя библиотеки задаётся без пути и без расширения. Например, если под Windows библиотека имеет имя myLib.dll, или под UNIX или Linux имеет имя myLib.so , надо указывать System.loadLibrary(“myLib”);
В случае, если файла не найдено, возбуждается непроверяемая исключительная ситуация UnsatisfiedLinkError.
Если требуется указать имя библиотеки с путём, применяется вызов
System.load (“ИмяБиблиотекиСПутём”);
Который во всём остальном абсолютно аналогичен вызову loadLibrary.
После того, как библиотека загружена, с точки зрения использования в программе вызов “родного” метода ничем не отличается от вызова любого другого метода.
Для создания библиотеки с методами, предназначенными для работы в качестве “родных”, обычно используется язык С++. В JDK существует утилита javah.exe, предназначенная для создания заголовков C++ из скомпилированных классов Java. Покажем, как ей пользоваться, на примере класса ClassWithNativeMethod. Зададим его
в пакете нашего приложения:
package java_example_pkg;
public class ClassWithNativeMethod {
/** Creates a new instance of ClassWithNativeMethod */
public ClassWithNativeMethod() {
}
public native void myNativeMethod();
}
Для того, чтобы воспользоваться утилитой javah, скомпилируем проект и перейдём в папку build\classes . В ней будут располагаться папка с пакетом нашего приложения java_example_pkg и папка META-INF. В режиме командной строки выполним команду
javah.exe java_example_pkg.ClassWithNativeMethod
- задавать имя класса необходимо с полной квалификацией, то есть с указанием перед ним имени пакета. В результате в папке появится файл java_example_pkg_ClassWithNativeMethod.h со следующим содержимым:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class java_example_pkg_ClassWithNativeMethod */
#ifndef _Included_java_example_pkg_ClassWithNativeMethod
#define _Included_java_example_pkg_ClassWithNativeMethod
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: java_example_pkg_ClassWithNativeMethod
* Method: myNativeMethod
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_java_1example_1pkg_ClassWithNativeMethod_myNativeMethod
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
Функция Java_java_1example_1pkg_ClassWithNativeMethod_myNativeMethod(JNIEnv *, jobject), написанная на C++, должна обеспечивать реализацию метода myNativeMethod() в классе Java. Имя функции C++ состоит из: префикса Java, разделителя “_”, модифицированного имени пакета (знаки подчёркивания “_” заменяются на “_1”), разделителя “_”, имени класса, разделителя “_”, имени “родного” метода.
Первый параметр JNIEnv * в функции C++ обеспечивает доступ “родного” кода к параметрам и объектам, передающимся из функции C++ в Java. В частности, для доступа к стеку. Второй параметр, jobject , – ссылка на экземпляр класса, в котором задан “родной” метод, для методов объекта, и jclass – ссылка на сам класс – для методов класса. В языке C++ нет ссылок, но в Java все переменные объектного типа являются ссылками. Соответственно, второй параметр отождествляется с этой переменной.
Если в “родном” методе имеются параметры, то список параметров функции C++ расширяется. Например, если мы зададим метод
public native int myNativeMethod(int i);
то список параметров функции C++ станет
(JNIEnv *, jobject, jint)
А тип функции станет jint вместо void.
Соответствие типов Java и C++:
Тип Java | Тип JNI (C++) | Характеристика типа JNI |
boolean | jboolean | 1 байт, беззнаковый |
byte | jbyte | 1 байт |
char | jchar | 2 байта, беззнаковый |
short | jshort | 2 байта |
int | jint | 4 байта |
long | jlong | 8 байт |
float | jfloat | 4 байта |
double | jdouble | 8 байт |
void | void | - |
Object | jobject | Базовый для остальных классов |
Class | jclass | Ссылка на класс Java |
String | jstring | Строки Java |
массив | jarray | Базовый для классов массивов |
Object[] | jobjectArray | Массив объектов |
boolean[] | jbooleanArray | Массив булевских значений |
byte[] | jbyteArray | Массив байт (знаковых значений длиной в байт) |
char[] | jcharArray | Массив кодов символов |
short[] | jshortArray | Массив коротких целых |
int[] | jintArray | Массив целых |
long[] | jlongArray | Массив длинных целых |
float[] | jfloatArray | Массив значений float |
double[] | jdoubleArray | Массив значений double |
Throwable | jthrowable | Обработчик исключительных ситуаций |
В реализации метода требуется объявить переменные. Например, если мы будем вычислять квадрат переданного в метод значения и возвращать в качестве результата значение параметра, возведённое в квадрат (пример чисто учебный), код реализации функции на C++ будет выглядеть так:
#include ”java_example_pkg_ClassWithNativeMethod.h”
JNIEXPORT jint JNICALL Java_java_1example_1pkg_ClassWithNativeMethod_myNativeMethod
(JNIEnv *env, jobject obj, jint i ){
return i*i
};
Отметим, что при работе со строками и массивами для получения и передачи параметров требуется использовать переменную env. Например, получение длины целого массива, переданного в переменную jintArray intArr, будет выглядеть так:
jsize length=(*env)->GetArrayLength(env, intArr);
Выделение памяти под переданный массив:
jint *intArrRef=(*env)->GetIntArrayElements(env, intArr,0);
Далее с массивом intArr можно работать как с обычным массивом C++.
Высвобождение памяти из-под массива:
(*env)->ReleaseIntArrayElements(env, intArr, intArrRef ,0);
Имеются аналогичные функции для доступа к элементам массивов всех примитивных типов:
GetBooleanArrayElements, GetByteArrayElements,…, GetDoubleArrayElements. Эти функции копируют содержимое массивов Java в новую область памяти, с которой и идёт работа в C++. Для массивов объектов имеется не только функция GetObjectArrayElement, но и SetObjectArrayElement – для получения и изменения отдельных элементов таких массивов.
Строка Java jstring s преобразуется в массив символов C++ так:
const char *sRef=(*env)->GetStringUTFChars(env,s,0);
Её длина находится как int s_len=strlen(sRef);
Высвобождается из памяти как
(*env)->ReleaseStringUTFChars(env,s,sRef);
- Содержание
- Глава 1. Общие представления о языке Java 6
- Глава 2. Объектно-ориентированное проектирование и платформа NetBeans 26
- Глава 3. Примитивные типы данных и операторы для работы с ними 78
- Глава 4. Работа с числами в языке Java 95
- Глава 5. Управляющие конструкции 112
- Глава 6. Начальные сведения об объектном программировании 128
- Глава 7. Важнейшие объектные типы 175
- Введение
- Глава 1. Общие представления о языке Java
- 1.1. Java и другие языки программирования. Системное и прикладное программирование
- 1.2. Виртуальная Java-машина, байт-код, jit-компиляция. Категории программ, написанных на языке Java
- 1.3.Алфавит языка Java. Десятичные и шестнадцатеричные цифры и целые числа. Зарезервированные слова Алфавит языка Java
- Десятичные и шестнадцатеричные цифры и целые числа
- Зарезервированные слова языка Java
- 1.4. Управляющие последовательности. Символы Unicode. Специальные символы Управляющие последовательности
- Простые специальные символы
- Составные специальные символы
- 1.5.Идентификаторы. Переменные и типы. Примитивные и ссылочные типы
- Краткие итоги по главе 1
- Задания
- Глава 2. Объектно-ориентированное проектирование и платформа NetBeans
- 2.1.Процедурное и объектно-ориентированное программирование. Инкапсуляция
- 2.2. Работа со ссылочными переменными. Сборка мусора
- 2.3. Проекты NetBeans. Пакеты. Уровни видимости классов. Импорт классов
- 2.4. Базовые пакеты и классы Java
- 2.5. Создание в NetBeans простейшего приложения Java
- 2.6. Компиляция файлов проекта и запуск приложения
- 2.7. Структура проекта NetBeans
- 2.8. Создание в NetBeans приложения Java с графическим интерфейсом
- 2.9. Редактор экранных форм
- 2.10. Внешний вид приложения
- 2.11. Ведение проектов
- 2.11. Редактирование меню экранной формы
- 2.12. Создание нового класса
- 2.13. Документирование исходного кода в Java
- 2.14. Основные компоненты пакетов swing и awt
- 2.15. Технологии Java и .Net
- Краткие итоги по главе 2
- Задания
- Глава 3. Примитивные типы данных и операторы для работы с ними
- 3.1.Булевский (логический) тип
- 3.2.Целые типы, переменные, константы
- 3.3.Основные операторы для работы с целочисленными величинами
- 3.4.Вещественные типы и класс Math
- 3.5.Правила явного и автоматического преобразования типа при работе с числовыми величинами
- 3.6. Оболочечные классы. Упаковка (boxing) и распаковка (unboxing)
- 3.7.Приоритет операторов
- 3.8.Типы-перечисления (enum)
- Краткие итоги по главе 3
- Задания
- Глава 4. Работа с числами в языке Java
- 4.1 Двоичное представление целых чисел Позиционные и непозиционные системы счисления
- Двоичное представление положительных целых чисел
- Двоичное представление отрицательных целых чисел. Дополнительный код
- Проблемы целочисленной машинной арифметики
- Шестнадцатеричное представление целых чисел и перевод из одной системы счисления в другую
- 4.2. Побитовые маски и сдвиги
- 4.3. Двоичное представление вещественных чисел Двоичные дроби
- Мантисса и порядок числа
- Стандарт ieee 754 представления чисел в формате с плавающей точкой*
- Краткие итоги по главе 4
- Задания
- Глава 5. Управляющие конструкции Составной оператор
- Условный оператор if
- Оператор выбора switch
- Условное выражение …?... : …
- Оператор цикла for
- Оператор цикла while – цикл с предусловием
- Оператор цикла do...While – цикл с постусловием
- Операторы прерывания continue, break, return, System.Exit
- Краткие итоги по главе 5
- Задания
- Глава 6. Начальные сведения об объектном программировании
- Наследование и полиморфизм. Uml-диаграммы
- Функции. Модификаторы. Передача примитивных типов в функции
- Локальные и глобальные переменные. Модификаторы доступа и правила видимости. Ссылка this
- Передача ссылочных типов в функции. Проблема изменения ссылки внутри подпрограммы
- Наследование. Суперклассы и подклассы. Переопределение методов
- Наследование и правила видимости. Зарезервированное слово super
- Статическое и динамическое связывание методов. Полиморфизм
- Базовый класс Object
- Конструкторы. Зарезервированные слова super и this. Блоки инициализации
- Удаление неиспользуемых объектов и метод finalize. Проблема деструкторов для сложно устроенных объектов
- Перегрузка методов
- Правила совместимости ссылочных типов как основа использования полиморфного кода. Приведение и проверка типов
- Рефакторинг
- Reverse engineering – построение uml-диаграмм по разработанным классам
- Краткие итоги по главе 6
- Задания
- Глава 7. Важнейшие объектные типы Массивы
- Коллекции, списки, итераторы
- Работа со строками в Java. Строки как объекты. Классы String, StringBuffer и StringBuilder
- Работа с графикой
- Исключительные ситуации Обработка исключительных ситуаций
- Иерархия исключительных ситуаций
- Объявление типа исключительной ситуации и оператор throw
- Объявление метода, который может возбуждать исключительную ситуацию. Зарезервированное слово throws
- Работа с файлами и папками
- Краткие итоги по главе 7
- Задания
- Глава 8. Наследование: проблемы и альтернативы. Интерфейсы. Композиция Проблемы множественного наследования классов. Интерфейсы
- Отличия интерфейсов от классов. Проблемы наследования интерфейсов
- Пример на использование интерфейсов
- Композиция как альтернатива множественному наследованию
- Краткие итоги по главе 8
- Задания
- Глава 9. Дополнительные элементы объектного программирования на языке Java Потоки выполнения (threads) и синхронизация
- Преимущества и проблемы при работе с потоками выполнения
- Синхронизация по ресурсам и событиям
- Класс Thread и интерфейс Runnable. Создание и запуск потока выполнения
- Поля и методы, заданные в классе Thread
- Подключение внешних библиотек dll.“Родные” (native) методы*
- Краткие итоги по главе 9
- Задания
- Глава 10. Введение в сетевое программирование Краткая справка по языку html
- Апплеты
- Сервлеты
- Технология jsp – Java Server Pages
- Краткие итоги по главе 10
- Задания
- Глава 11. Встроенные классы Виды встроенных классов
- Вложенные (nested) классы и интерфейсы
- Внутренние (inner) классы
- Локальные (local) классы
- Анонимные (anonimous) классы и обработчики событий
- Анонимные (anonimous) классы и слушатели событий (listeners)
- Краткие итоги по главе 11
- Задания
- Глава 12. Компонентное программирование Компонентная архитектура JavaBeans
- Мастер создания компонента в NetBeans
- Пример создания компонента в NetBeans – панель с заголовком
- Добавление в компонент новых свойств
- Добавление в компонент новых событий
- Краткие итоги по главе 12
- Задания
- Литература
- Дополнительная литература
- 276 Курс подготовлен при поддержке Sun Microsystems