Java Language
자바 네이티브 인터페이스
수색…
매개 변수
매개 변수 | 세부 |
---|---|
JNIEnv | JNI 환경의 포인터 |
작업 | static 가 아닌 native 메소드를 호출 한 객체 |
jclass | static native 메소드를 호출 한 클래스 |
비고
JNI를 설정하려면 Java 컴파일러와 원시 컴파일러가 모두 필요합니다. IDE와 OS에 따라 몇 가지 설정이 필요합니다. Eclipse에 대한 안내서는 여기 에서 찾을 수 있습니다 . 전체 자습서는 여기 에서 찾을 수 있습니다 .
다음은 Windows에서 Java-C ++ 링키지를 설정하는 단계입니다.
-
javac
사용하여 Java 소스 파일 (.java
)을 클래스 (.class
)로javac
. -
javah
사용하는native
메소드가 들어있는 Java 클래스에서 헤더 (.h
) 파일을javah
. 이러한 파일은 구현할 책임이있는 메소드를 네이티브 코드에 "지시"합니다. -
native
메소드를 구현하는 C ++ 소스 파일 (.cpp
)에 헤더 파일 (#include
)을 포함시킵니다. - C ++ 소스 파일을 컴파일하고 라이브러리 (
.dll
)를 만듭니다. 이 라이브러리에는 원시 코드 구현이 포함되어 있습니다. - 라이브러리 경로 (
-Djava.library.path
)를 지정하고 Java 소스 파일 (System.loadLibrary(...)
)에로드하십시오.
콜백 (원시 코드에서 Java 메소드 호출)은 메소드 설명자를 지정해야합니다. 설명자가 올바르지 않으면 런타임 오류가 발생합니다. 이 때문에 javap -s
를 사용하여 설명자를 작성하는 것이 도움이됩니다.
자바에서 C ++ 메소드 호출하기
Java의 정적 및 구성원 메소드는 해당 구현이 공유 라이브러리 파일에서 발견 될 것임을 나타 내기 위해 원시 로 표시 될 수 있습니다. 네이티브 메소드를 실행하면 JVM은로드 된 라이브러리 ( 네이티브 라이브러리로드 참조)에서 해당 함수를 찾고 단순한 이름 변환 체계를 사용하여 인수 변환 및 스택 설정을 수행 한 다음 제어를 원시 코드로 넘깁니다.
Java 코드
/*** com/example/jni/JNIJava.java **/
package com.example.jni;
public class JNIJava {
static {
System.loadLibrary("libJNI_CPP");
}
// Obviously, native methods may not have a body defined in Java
public native void printString(String name);
public static native double average(int[] nums);
public static void main(final String[] args) {
JNIJava jniJava = new JNIJava();
jniJava.printString("Invoked C++ 'printString' from Java");
double d = average(new int[]{1, 2, 3, 4, 7});
System.out.println("Got result from C++ 'average': " + d);
}
}
C ++ 코드
원시 함수 선언을 포함하는 헤더 파일은 대상 클래스의 javah
도구를 사용하여 생성해야합니다. 빌드 디렉토리에서 다음 명령을 실행하십시오.
javah -o com_example_jni_JNIJava.hpp com.example.jni.JNIJava
... 다음 헤더 파일을 생성합니다 ( 간결하게 주석을 제거했습니다 ).
// com_example_jni_JNIJava.hpp
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h> // The JNI API declarations
#ifndef _Included_com_example_jni_JNIJava
#define _Included_com_example_jni_JNIJava
#ifdef __cplusplus
extern "C" { // This is absolutely required if using a C++ compiler
#endif
JNIEXPORT void JNICALL Java_com_example_jni_JNIJava_printString
(JNIEnv *, jobject, jstring);
JNIEXPORT jdouble JNICALL Java_com_example_jni_JNIJava_average
(JNIEnv *, jclass, jintArray);
#ifdef __cplusplus
}
#endif
#endif
다음은 구현 예입니다.
// com_example_jni_JNIJava.cpp
#include <iostream>
#include "com_example_jni_JNIJava.hpp"
using namespace std;
JNIEXPORT void JNICALL Java_com_example_jni_JNIJava_printString(JNIEnv *env, jobject jthis, jstring string) {
const char *stringInC = env->GetStringUTFChars(string, NULL);
if (NULL == stringInC)
return;
cout << stringInC << endl;
env->ReleaseStringUTFChars(string, stringInC);
}
JNIEXPORT jdouble JNICALL Java_com_example_jni_JNIJava_average(JNIEnv *env, jclass jthis, jintArray intArray) {
jint *intArrayInC = env->GetIntArrayElements(intArray, NULL);
if (NULL == intArrayInC)
return -1;
jsize length = env->GetArrayLength(intArray);
int sum = 0;
for (int i = 0; i < length; i++) {
sum += intArrayInC[i];
}
env->ReleaseIntArrayElements(intArray, intArrayInC, 0);
return (double) sum / length;
}
산출
위의 예제 클래스를 실행하면 다음과 같은 결과가 출력됩니다.
Java에서 C ++ 'printString'호출
C ++에서 얻은 결과 'average': 3.4
C ++ (콜백)에서 Java 메소드 호출
원시 코드에서 Java 메소드 호출은 두 단계 프로세스입니다.
- 메서드 명과 기술자를 사용해,
GetMethodID
JNI 함수를 가지는 메서드 포인터를 취득한다. - 여기에 나열된
Call*Method
함수 중 하나를Call*Method
하십시오 .
Java 코드
/*** com.example.jni.JNIJavaCallback.java ***/
package com.example.jni;
public class JNIJavaCallback {
static {
System.loadLibrary("libJNI_CPP");
}
public static void main(String[] args) {
new JNIJavaCallback().callback();
}
public native void callback();
public static void printNum(int i) {
System.out.println("Got int from C++: " + i);
}
public void printFloat(float i) {
System.out.println("Got float from C++: " + i);
}
}
C ++ 코드
// com_example_jni_JNICppCallback.cpp
#include <iostream>
#include "com_example_jni_JNIJavaCallback.h"
using namespace std;
JNIEXPORT void JNICALL Java_com_example_jni_JNIJavaCallback_callback(JNIEnv *env, jobject jthis) {
jclass thisClass = env->GetObjectClass(jthis);
jmethodID printFloat = env->GetMethodID(thisClass, "printFloat", "(F)V");
if (NULL == printFloat)
return;
env->CallVoidMethod(jthis, printFloat, 5.221);
jmethodID staticPrintInt = env->GetStaticMethodID(thisClass, "printNum", "(I)V");
if (NULL == staticPrintInt)
return;
env->CallVoidMethod(jthis, staticPrintInt, 17);
}
산출
C ++에서 부동 소수점 가져 오기 : 5.221
C ++에서 가져온 int : 17
설명자 가져 오기
설명자 (또는 내부 형식 서명 )는 컴파일 된 .class
파일의 javap 프로그램을 사용하여 가져옵니다. 다음은 javap -p -s com.example.jni.JNIJavaCallback
의 결과입니다.
Compiled from "JNIJavaCallback.java"
public class com.example.jni.JNIJavaCallback {
static {};
descriptor: ()V
public com.example.jni.JNIJavaCallback();
descriptor: ()V
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
public native void callback();
descriptor: ()V
public static void printNum(int);
descriptor: (I)V // <---- Needed
public void printFloat(float);
descriptor: (F)V // <---- Needed
}
네이티브 라이브러리로드 중
Java에서 공유 라이브러리 파일을로드하는 일반적인 관용구는 다음과 같습니다.
public class ClassWithNativeMethods {
static {
System.loadLibrary("Example");
}
public native void someNativeMethod(String arg);
...
System.loadLibrary
대한 호출은 거의 항상 정적이므로 클래스로드 중에 발생하므로 공유 라이브러리가로드되기 전에 원시 메소드를 실행할 수 없습니다. 그러나 다음이 가능합니다.
public class ClassWithNativeMethods {
// Call this before using any native method
public static void prepareNativeMethods() {
System.loadLibrary("Example");
}
...
이렇게하면 필요 할 때까지 공유 라이브러리 로딩을 지연 할 수 있지만 java.lang.UnsatisfiedLinkError
를 피하기 위해 추가로주의해야합니다.
대상 파일 조회
공유 라이브러리 파일은 런타임시 -Djava.library.path=
JVM 인수를 사용하여 재정의 할 수있는 java.library.path
시스템 특성으로 정의 된 경로에서 검색됩니다.
java -Djava.library.path=path/to/lib/:path/to/other/lib MainClassWithNativeMethods
시스템 경로 구분 기호에주의하십시오 (예 : Windows 사용 ;
대신 :
.
System.loadLibrary
는 플랫폼에 따라 라이브러리 파일 이름을 확인합니다. 위의 코드는 Linux의 libExample.so
파일과 Windows의 Example.dll
파일을 필요로합니다.
System.loadLibrary
의 대안은 System.load(String)
.이 라이브러리는 java.library.path
조회를 우회하여 공유 라이브러리 파일의 전체 경로를 사용합니다.
public class ClassWithNativeMethods {
static {
System.load("/path/to/lib/libExample.so");
}
...