JNI
步骤1:编写java代码
import java.util.Scanner;
public class HelloJNI {
static {
System.loadLibrary("HelloWorld");
}
public native static void setNum(int num);
public native static void setStr(String str);
public native static int get();
public static void main(String[] args) {
HelloJNI test = new HelloJNI();
test.setNum(666);
System.out.println(test.get());
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println("请输入字符串:");
String str = scanner.nextLine();
if (str.equals("quit")) {
break;
}
test.setStr(str);
}
}
}
步骤2:编译成class文件
javac HelloJNI
步骤3:编译成HelloJNI.h文件
使用javah工具将.class文件编译成.h文件
javah -jni HelloJNI
编译后的.h文件中包含了java调用的c方法名,内容如下。
/* 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: setNum
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_HelloJNI_setNum
(JNIEnv *, jclass, jint);
/*
* Class: HelloJNI
* Method: setStr
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_HelloJNI_setStr
(JNIEnv *, jclass, jstring);
/*
* Class: HelloJNI
* Method: get
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_HelloJNI_get
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
步骤4:编写c的实现
#include "HelloJNI.h"
#include "stdio.h"
int result=888;
JNIEXPORT void JNICALL Java_HelloJNI_setNum
(JNIEnv * env, jclass jc, jint num){
result+=num;
}
JNIEXPORT jint JNICALL Java_HelloJNI_get
(JNIEnv * env, jclass jc){
return result;
}
JNIEXPORT void JNICALL Java_HelloJNI_setStr
(JNIEnv * env, jclass jc, jstring str){
const char *c_str = env->GetStringUTFChars(str, NULL);
if (c_str != NULL) {
printf("C_Rx: %s\n", c_str);
env->ReleaseStringUTFChars(str, c_str);
}
}
步骤5:收集文件
将步骤3生成的HelloJNI.h文件放在c文件的同级目录
步骤6:将cpp文件编译成dll文件
使用gcc将.c或.cpp文件编译成dll文件(windows平台),linux平台需要编译成.so文件。
gcc -shared -o 文件名.dll -I"%JAVA_HOME%\include" -I"%JAVA_HOME%\include\win32" c文件名.cpp
JAVA_HOME是自己配置的环境变量,Java开发人员应该都懂。
需要注意的是linux平台下
-
%JAVA_HOME%
需要换成$JAVA_HOME
-
%JAVA_HOME%\include\win32
需要换成linux平台的$JAVA_HOME/include/linux
步骤7:移动DLL文件
将编译的dll文件放在 HelloJNI.class同级目录下
步骤8:运行
Java HelloJNI
JNA
步骤1:确定c中定义的接口
dll.h头文件如下。
#ifndef _DLL_H_
#define _DLL_H_
#ifdef __cplusplus
extern "C" {
#endif
#if BUILDING_DLL
#define DLLIMPORT __declspec(dllexport)
#else
#define DLLIMPORT __declspec(dllimport)
#endif
DLLIMPORT void HelloWorld();
DLLIMPORT const char* helloJna();
#ifdef __cplusplus
}
#endif
#endif
dllmain.c文件如下。
/* Replace "dll.h" with the name of your header */
#include "dll.h"
#include <windows.h>
DLLIMPORT void HelloWorld()
{
MessageBox(0,"Hello World from DLL!\n","Hi",MB_ICONINFORMATION);
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
{
switch(fdwReason)
{
case DLL_PROCESS_ATTACH:
{
break;
}
case DLL_PROCESS_DETACH:
{
break;
}
case DLL_THREAD_ATTACH:
{
break;
}
case DLL_THREAD_DETACH:
{
break;
}
}
/* Return TRUE on success, FALSE on failure */
return TRUE;
}
DLLIMPORT const char* helloJna()
{
return "Hello Jna-20240105";
}
与JNI不同的是,JNA方式中不用自己写C语言代码,只需要知道C的调用接口就行了,以上面给出的代码为例,接口为HelloWorld
和helloJna
。注意JNA调用性能会有损耗,性能大致为JNI的1/10。
步骤2:编译成DLL文件,移动DLL文件
-
将c编译dll的过程略
-
将DLL文件移动到调用方java文件所在的同级目录,本案例编译的dll名称为:
jna_c.dll
步骤3:编写java代码
import com.sun.jna.Library;
import com.sun.jna.Native;
public class JNA {
public interface SampleLibrary extends Library {
SampleLibrary INSTANCE = Native.load("jna_c", SampleLibrary.class);
void HelloWorld();
String helloJna();
}
public static void main(String[] args) {
// INSTANCE为SampleLibrary接口的实例,通过Native.load进行初始化,使用INSTANCE.方法名就可以调用本地代码(c程序)
SampleLibrary.INSTANCE.HelloWorld();
String result = SampleLibrary.INSTANCE.helloJna();
System.out.println(result);
}
}
注意:Library
和Native
都是com.sun.jna
包下的,所以需要下载对应的jna包。
-
jar包下载地址:https://repo1.maven.org/maven2/net/java/dev/jna/jna/
-
使用maven方式:
-
<dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna</artifactId> <version>5.13.0</version> </dependency>
-
步骤4:编译成class
-
将jna包移动到java文件同级目录。
-
javac -classpath jna-5.13.0.jar JNA.java
步骤5:运行
-
此时目录下需包含以下文件
- jna-5.13.0.jar
- JNA$SampleLibrary.class
- JNA.class
- jna_c.dll
-
java -cp .;jna-5.13.0.jar JNA
- 这个命令会将当前目录 (
.
) 和jna-5.13.0.jar
都添加到类路径上,并运行JNA
类。如果你在 Linux 或 macOS 上运行,使用分号;
的地方应该改成冒号:
。
- 这个命令会将当前目录 (