我们来看下一个简单的JNI示例,JAVA代码如下:
1)编写声明了native方法的Java类
public class JniHelloWord {
/**
* native关键字,表明这个方法使用java以外的语言实现,方法不包括实现,因为我们要用c/c++语言实现它
*/
public native void printHelloWorld();
static {
//System.loadLibrary("hello")这句代码,它是在静态初始化块中定义的,系统用来装载hello库,
//这就是我们在后面生成的hello.dll
System.loadLibrary("hello");
}
public static void main(String[] args) {
new JniHelloWord().printHelloWorld();
}
}
2)将Java源代码编译成class字节码文件
在目录下执行:
javac -encoding UTF-8 JniHelloWord.java
3)用javah 命令生成.h头文件
在目录下执行:
javah JniHelloWord
会生成JniHelloWord.h头文件,就像java是运行main方法一样,javah就是提供具有native method的java对象的c函数接口,内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class JniHelloWord */
#ifndef _Included_JniHelloWord
#define _Included_JniHelloWord
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: JniHelloWord
* Method: printHelloWorld
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_JniHelloWord_printHelloWorld
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
最重要的C函数接口就是这样:
JNIEXPORT void JNICALL Java_JniHelloWord_printHelloWorld(JNIEnv *, jobject);
JNIEXPORT :在Jni编程中所有本地语言实现Jni接口的方法前面都有一个"JNIEXPORT",这个可以看做是Jni的一个标志,是用于导出函数的、依赖于编译器的指示符。返回类型是映射到 Java 类型的 C/C++ 类型
void :这个学过编程的人都知道,当然是方法的返回值了。
JNICALL :这个可以理解为Jni 和Call两个部分,和起来的意思就是 Jni调用XXX(后面的XXX就是JAVA的方法名)。
Java_JniHelloWord_printHelloWorld:这个就是被上一步中被调用的部分,也就是Java中的native 方法名,这里起名字的方式比较特别,是:包名+类名+方法名。
JNIEnv * env:这个env可以看做是Jni接口本身的一个对象,jni.h头文件中存在着大量被封装好的函数,这些函数也是Jni编程中经常被使用到的,要想调用这些函数就需要使用JNIEnv这个对象。例如:env->GetObjectClass()。(详情请查看jni.h)
jobject obj:代表着native方法的调用者,本例即new JniHelloWord();但如果native是静态的,那就是JniHelloWord.class .
也就是说,我们的native printHelloWorld()方法实际上是运行C的Java_JniHelloWord_printHelloWorld()这个方法,我们是不能随意写C函数名的的,只能这样写。
关于jni.h头文件
它实际上就存在%JAVA_HOME%\include下面的一个文件,另外还有个%JAVA_HOME%\include\win32下的jni_md.h.
jni.h头文件主要定义了以下内容,图片来自网上:
4)用本地代码实现.h头文件中的函数
接下来我们可以照着接口去写真正的函数方法了.新建JniHelloWord.cpp,我这用的是Visual Studio 2019,步骤如下,新建一个项目,选择“动态链接库(DLL)”
复制3个文件到目录中
VS添加到头文件目录中
修改JniHelloWord.h 文件
#include <jni.h> 改为 #include "jni.h"
然后新建HellowWorld.cpp文件
输入如下代码:
// JniHelloWord.cpp : 定义 DLL 的导出函数。
//
#include "JniHelloWord.h"
#include "jni.h" //注意添加这句
#include<iostream>
using namespace std;
JNIEXPORT void JNICALL Java_JniHelloWord_printHelloWorld(JNIEnv* env, jobject obj)
{
cout << "Hello World!" << endl;
cout << "I come from C++!" << endl;
}
5)将本地代码编译成动态库(windows:*.dll,linux/unix:*.so,mac os x:*.jnilib)
解决方案右击-》 配置管理器,
然后点击生成
6)复制这个dll文件,改名hello.dll 并放在项目路径下面
7)测试
在该项目下执行
java JniHelloWord
输出如下:
如果报错:
Can't load IA 32-bit .dll on a AMD 64-bit platform
在活动解决平台方案选择 x64