博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JNI HelloWorld的例子
阅读量:4209 次
发布时间:2019-05-26

本文共 4665 字,大约阅读时间需要 15 分钟。

1.编写JAVA代码

新建Project 编写Hello.java类

这里写图片描述

Hello.java

package com.hqq;/** * Hello * Created by heqianqian on 2017/4/15. */public class Hello {
//定义本地方法 private native void sayHello(); public static void main(String[] args) { //调用动态链接库 System.loadLibrary("Hello"); Hello hello = new Hello(); hello.sayHello(); }}

函数System.loadLibrary()是加载dll(windows)或so(Linux)库,只需名称即可,无需加入文件名后缀(.dll或.so)。

native关键字将函数sayHello()声明为本地函数,由C/C++实现。具体的实现就在hello.dll(Windows平台)或hello.so(Linux平台)中

2.生成JNI头文件

1 ) 手动输入javah指令

JNI生成头文件是通过JDK中提供的javah来完成,javah在 {JDKHome}/bin目录中。用法如下:

javah -jni -classpath (搜寻类目录) -d (输出目录) (类名)

需要注意的是,使用javah来生成头文件(.h)时,-classpath指定的是编译后的java文件(.class)的目录,而不是源文件(.java)的目录,因此在使用javah指令之前,先build一下项目(或直接运行一下)。此时会生称out目录,所有编译后的文件都会存放在这个目录中。

这里写图片描述

在IDEA的控制台下输入指令

这里写图片描述

javah -classpath F:\Workspaces\JavaWorkspace\JNIDemo1\out\production\JNIDemo1 -d F:\Workspaces\JavaWorkspace\JNIDemo1\lib com.hqq.Hello

可以看到在lib文件夹下生成了com_hqq_Hello.h文件

这里写图片描述

这里注意两点

javah -jni -classpath (搜寻类目录) -d (输出目录) (类名)
  1. 搜索类目录不要进入包目录 否则会提示找不到类
  2. 类名要写全且不用加.java后缀

生成的头文件内容如下

/* DO NOT EDIT THIS FILE - it is machine generated */#include 
/* Header for class com_hqq_Hello */#ifndef _Included_com_hqq_Hello#define _Included_com_hqq_Hello#ifdef __cplusplusextern "C" {#endif/* * Class: com_hqq_Hello * Method: sayHello * Signature: ()V */JNIEXPORT void JNICALL Java_com_hqq_Hello_sayHello (JNIEnv *, jobject);#ifdef __cplusplus}#endif#endif

接下来我们只需实现Java_com_huachao_java_HelloJNI_sayHello(JNIEnv *, jobject)即可。

仔细观察就会发现这个函数名称是有规律的,即

Java_
<包>
_
<类名>
_
<函数名>

JNIEXPORT和JNICALL这两个宏定义暂时不用管。JNIEnv 和jobject后面系列文章会详细介绍,这里暂时不理会。

2 ) 一键生成头文件

点击File>Settings>Tools>External Tools:

这里写图片描述

添加一个新的External Tools:

这里写图片描述

在HelloJNI.java文件中点击右键>External Tools>Generate Header File

这里写图片描述

这里写图片描述

点击生成,可以看到Terminal窗口会自动运行指令

3. 编写C文件并编译成dll(或so)文件

命令行生成dll

在jni目录下新建Hello.c文件 实现Java_com_huachao_java_HelloJNI_sayHello(JNIEnv *, jobject)函数

##include
#include
#include"com_hqq_Hello.h"/* * Class: com_hqq_Hello * Method: sayHello * Signature: ()V */JNIEXPORT void JNICALL Java_com_hqq_Hello_sayHello(JNIEnv *env, jobject obj){ printf("hello,jni!"); printf("hello,world!"); return ;}

接下来就是使用GCC对HelloJNI.c编译,在Terminal窗口输入如下:

gcc -c jni/Hello.c

提示找不到 jni.h

F:\Workspaces\JavaWorkspace\JNIDemo1>gcc -c jni/Hello.cjni/Hello.c:1:16: fatal error: jni.h: No such file or directory #include
^compilation terminated.

将JDK目录中的include目录加入

gcc -c -I"E:\Program Files\Java\jdk1.8\include" jni/Hello.c

又提示找不到 jni_md.h

F:\Workspaces\JavaWorkspace\JNIDemo1>gcc -c -I"E:\Program Files\Java\jdk1.8\include" jni/Hello.cIn file included from jni/Hello.c:1:0:E:\Program Files\Java\jdk1.8\include/jni.h:45:20: fatal error: jni_md.h: No such file or directory #include "jni_md.h"

继续将JDK目录中的include/win32加入

gcc -c -I"E:\Program Files\Java\jdk1.8\include" -I"E:\Program Files\Java\jdk1.8\include\win32" jni/Hello.c

这次运行成功 在项目根目录下生成了Hello.o

接下来是将HelloJNI.o转为HelloJNI.dll,即转为windows平台下的动态链接库

输入

gcc -Wl,--add-stdcall-alias -shared -o hello.dll Hello.o

结果项目目录中生成了hello.dll文件:

这里写图片描述

一键生成dll

File>Settings>Tools>External Tools>+

输入内容

name:Generate DLLProgram:
Parameters:-Wl,--add-stdcall-alias -I"$JDKPath$\include" -I"$JDKPath$\include\win32" -shared -o ./lib/$FileNameWithoutExtension$.dll ./jni/$FileNameWithoutExtension$.cWorking Directory:$ProjectFileDir$

这里配置将jni下.c文件生成.dll文件放在lib目录下

首先看生成dll文件前项目目录

这里写图片描述

生成之后

这里写图片描述

4. 运行

这里写图片描述

5.可能出现的错误

java.library.path找不到dll的错误

Exception in thread "main" java.lang.UnsatisfiedLinkError: no Hello in java.library.path    at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867)    at java.lang.Runtime.loadLibrary0(Runtime.java:870)    at java.lang.System.loadLibrary(System.java:1122)    at com.hqq.Hello.main(Hello.java:14)

即找不到我们生成的dll文件。因为在Windows中JVM的java.library.path属性即为环境变量Path指定的目录,而我们生成的dll并未放入到Path指定的任何一个目录中,因此我们需要告诉JVM,dll文件在哪个目录中

点击Run > Edit Configurations…,如下:

在VM options中加入java.library.path,指定dll(或so)文件所在的目录,比如本文中dll放在项目目录中的lib中,如下:

-Djava.library.path=F:\Workspaces\JavaWorkspace\JNIDemo1\lib

无法识别__int64类型错误

error: unknown type name '__int64' typedef __int64 jlong;

出现这个错误的人一般是使用Cygwin GCC的人,这是因为Cygwin GCC不认识__int64类型,找到/include/win32/jni_md.h,找到typedef __int64 jlong;并修改为:

#ifdef __GNUC__typedef long long jlong;#elsetypedef __int64 jlong;#endif

或者是编译时将__int64加入,如下:

> gcc-3 -D __int64="long long" -mno-cygwin -Wl,--add-stdcall-alias   -I"
\include" -I"
\include\win32" -shared -o hello.dll HelloJNI.c

64-bit mode not compiled

HelloJNI.c:1:0: sorry, unimplemented: 64-bit mode not compiled in #include 

出现这个错误是因为,JDK版本是64位,而GCC编译器编译出的dll(或so)是32位,只需换个64位版本的GCC即可


参考文章:

你可能感兴趣的文章
11丨性能脚本:用案例和图示帮你理解HTTP协议
查看>>
12丨性能场景:做参数化之前,我们需要考虑什么?
查看>>
13丨性能测试场景:如何进行场景设计
查看>>
14丨性能测试场景:如何理解业务模型
查看>>
Prometheus exporter详解
查看>>
15丨性能测试场景:如何进行监控设计
查看>>
16丨案例:性能监控工具之Grafana-Prometheus-Exporters
查看>>
九度OJ 1085:求root(N, k) (迭代)
查看>>
九度OJ 1086:最小花费 (DP)
查看>>
九度OJ 1087:约数的个数 (数字特性)
查看>>
九度OJ 1088:剩下的树 (线段树)
查看>>
九度OJ 1089:数字反转 (数字反转)
查看>>
九度OJ 1090:路径打印 (树、DFS)
查看>>
九度OJ 1091:棋盘游戏 (DP、BFS、DFS、剪枝)
查看>>
九度OJ 1092:Fibonacci (递归)
查看>>
九度OJ 1093:WERTYU (翻译)
查看>>
九度OJ 1094:String Matching(字符串匹配) (计数)
查看>>
九度OJ 1095:2的幂次方 (递归)
查看>>
九度OJ 1471-1480(10/10)
查看>>
九度OJ 1481-1490(7/10)
查看>>