本文主要是介绍JNI调用C++方法指南,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
概述
JNI(Java Native Interface)用来在Java中调用其他语言编写的代码。本文主要介绍如何在Java中调用C++程序。
测试环境:Ubuntu 20.04.6 LTS, JDK 8, G++ 9.4.0
JNI的入门
Java中提供了native
关键字,用于指示方法实现由本地代码来提供。对于C++程序而言,可以将源码打包为静态库或动态库。在JNI中通常使用动态库,这样可以避免将Java字节码和本地代码混合在同一个的二进制文件中。
下面通过一个示例来演示JNI的具体用法。
步骤1:定义Java类HelloJNI
,其源代码如下:
public class HelloJNI {static {System.loadLibrary("native"); // 加载指定的本地库, 使得可以通过JNI调用库中定义的本地方法}public static void main(String[] args) {new HelloJNI().sayHello("Linux");}private native void sayHello(String name); // 通过native修饰的本地方法, 需要将其链接到本地代码实现
}
步骤2:通过命令javac -h . HelloJNI.java
编译Java源文件并自动生成C++头文件,生成的HelloJNI.h
的源码如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloJNI */#ifndef _Included_HelloJNI
#define _Included_HelloJNI
#ifdef __cplusplus
extern "C" {
#endif
/** Class: HelloJNI* Method: sayHello* Signature: (Ljava/lang/String;)V*/
JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *, jobject, jstring);#ifdef __cplusplus
}
#endif
#endif
本地方法声明JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *, jobject, jstring)
中包含三个参数:
JNIENV *
:代表Java环境,通过该指针可以对Java端的代码进行操作jobject
:代表该native方法对应的类对象实例。注意,若该native方法有static
修饰,则其代表这个native方法对应的类实例jstring
:传递的参数,对应Java中的String
类型
步骤3:定义头文件同名的文件HelloJNI.cpp
,并在其中实现sayHello()
方法:
#include "HelloJNI.h"
#include <iostream>JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JJNIEnv* env, jobject thisObject, jstring name){const char* str = env->GetStringUTFChars(name, NULL);std::cout << "Hello " << str << std::endl;
}
步骤4:编译C++代码为动态库:
# 获取.o文件
g++ -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux HelloJNI.cpp
# 打包
g++ -shared HelloJNI.o -o libnative.so
步骤5:运行Java代码:
java -Djava.library.path=. HelloJNI# 结果
Hello Linux
说明:
-Djava.library.path=.
:指定JVM查找本地库的路径为当前目录。
JNI的高级功能
JNI提供了一组特定的类型用于在C++和Java语言中传递数据。
基本数据类型
下表描述了Java基本类型在C++中对应的本地类型。
Java Type | Native Type | Description |
---|---|---|
boolean | jboolean | unsigned 8 bits |
byte | jbyte | signed 8 bits |
char | jchar | unsigned 16 bits |
short | jshort | signed 16 bits |
int | jint | signed 32 bits |
long | jlong | signed 64 bits |
float | jfloat | 32 bits |
double | jdouble | 64 bits |
void | void | not applicable |
引用类型
JNI还支持多种应用类型,其对应关系如下:
Java Type | Native Type | Description |
---|---|---|
Class | jclass | Class类型 |
Object | jobject | Java中的对象 |
String | jstring | 字符串 |
Object[] | jobjectArray | 对象类型数组 |
boolean[] | jbyteArray | 布尔型数组 |
char[] | jcharArray | 字符型数组 |
short[] | jshortArray | 短整型数组 |
int[] | jintArray | 整形数组 |
long[] | jlongArray | 长整型数组 |
float[] | jfloatArray | 浮点型数组 |
double[] | jdoubleArray | 双浮点型数组 |
使用示例
Java类源码:
public class TypeTest {static{System.loadLibrary("typetest");}public static void main(String[] args) {TypeTest test = new TypeTest();int[] arr = {3, 1, 5, 9, 2};System.out.println(test.add(4, 5));System.out.println(test.circle(5.0));int[] brr = test.sortArray(arr);for(int num:brr){System.out.print(num + " ");}System.out.println();}public native int add(int a, int b);public native double circle(double radius);public native int[] sortArray(int[] array);
}
C++类头文件:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class TypeTest */#ifndef _Included_TypeTest
#define _Included_TypeTest
#ifdef __cplusplus
extern "C" {
#endif
/** Class: TypeTest* Method: add* Signature: (II)I*/
JNIEXPORT jint JNICALL Java_TypeTest_add(JNIEnv *, jobject, jint, jint);/** Class: TypeTest* Method: circle* Signature: (D)D*/
JNIEXPORT jdouble JNICALL Java_TypeTest_circle(JNIEnv *, jobject, jdouble);/** Class: TypeTest* Method: sortArray* Signature: ([I)[I*/
JNIEXPORT jintArray JNICALL Java_TypeTest_sortArray(JNIEnv *, jobject, jintArray);#ifdef __cplusplus
}
#endif
#endif
C++类方法实现:
#include "TypeTest.h"
#include <algorithm>const double PI = 3.14;JNIEXPORT jint JNICALL Java_TypeTest_add(JNIEnv * env, jobject obj, jint a, jint b){return a + b;
}JNIEXPORT jdouble JNICALL Java_TypeTest_circle(JNIEnv * env, jobject obj, jdouble radius){return PI * radius * radius;
}JNIEXPORT jintArray JNICALL Java_TypeTest_sortArray(JNIEnv * env, jobject obj, jintArray arr){// 获取数组长度jsize length = env->GetArrayLength(arr);// 获取数组元素jint* elements = env->GetIntArrayElements(arr, 0);std::sort(elements, elements + length);// 创建新的 jintArray 并设置排序后的元素jintArray result = env->NewIntArray(length);env->SetIntArrayRegion(result, 0, length, elements);// 释放原始数组env->ReleaseIntArrayElements(arr, elements, 0);return result;
}
编译运行参考JNI入门章节,不作重复赘述。
结语
参考资料:
- Chapter 3: JNI Types and Data Structures
这篇关于JNI调用C++方法指南的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!