引言:
JNI,java本地接口。介绍跳过,搜索“JNI”有好大一票记录。网上例子灰常多,差不多只有3,4版的样子,而且不容易按文章的说明自行实现。因此本文,专门就调通一个流行的简单实例进行全程解说。
正文:
(家里电脑无环境,占楼,待续。)
(续上)
本例中,java侧为手工编写,以突出要点。C++侧的dll采用VS2010的win32_dll,以求简洁。
一、概要。
完成此JniDemo大体需要以下几步:
1,编写Java类;
2,编译为*.class文件;
3,编译出JNI头文件;
4,编写C++的dll;
5,部署dll运行*.class。
以下就每一步进行详细说明。
二、详细说明。
1,编写Java类。 需要注意的是确认本机JDK安装成功。另外为了突出重点,类不带包声明,以避免“找不到类”这类报错的干扰。代码如下:
import java.io.Serializable;
/*
* Copyright (c) 2010 CCX(China) Co.,Ltd. All Rights Reserved.
*
* This software is the confidential and proprietary information of
* CCX(China) Co.,Ltd. ("Confidential Information").
* It may not be copied or reproduced in any manner without the
* express written permission of CCX(China) Co.,Ltd.
*
* Author: zhnb
* Date: 2011-6-20 下午04:50:43
*/
public class JniHello implements Serializable {
private static final long serialVersionUID =
2683028985839110062L;
// JNI调用
public native void sayHi();
static {
System.loadLibrary("jniWin32");
}
// 自定义方法
public void sayHi(String str){
System.out.println("Hello, " + str + " !");
}
public static void main(String[] args) {
JniHello jniHello = new JniHello();
jniHello.sayHi();
jniHello.sayHi("Zhao");
}
}
以上代码没有啥解释的,文件名“JniHello.java”(笔者工作目录“E:\tecPoints\jni\”)。
2,编译为*.class文件。
A)“开始” | “运行” (或【窗口】+【R】组合键),输入
cmd
打开DOS命令窗口。
B)执行:
$E: $cd E:\tecPoints\jni $javac JniHello.java
其中“$”指代DOS命令提示符(比如“E:\tecPoints\jni>”)。此时工作目录(E:\tecPoints\jni\)生成一个文件“JniHello.class”。
3,编译出JNI头文件。
运行:
$javah -jni JniHello
此时在工作目录生成一个文件“JniHello.h”。为编写C++的dll而生成。目前工作目录下,共有3个文件,如图“files_in_workdir.jpg”。
4,编写C++的dll。
A)打开VS2010(笔者使用的旗舰版)。
B)操作“ 文件 | 新建 | 项目... ”,在左侧选择“ Visual C++ | win32 ” ,主栏中选择“win32 项目”。下边“名称”填入“jniWin32”,点确定。如图“create_win32DLL_project.jpg”。
在win32向导中,选择“Dll”。如图“create_win32DLL_project_asDLL.jpg”所示。
点击“完成”,即生成jniWin32项目。如图“jniWin32_project_fileView.jpg”所示。
此时,C++ DLL项目创建完成。
C)编写DLL。
(i)操作:右键项目“jniWin32” | 选择“在windows 资源管理器中打开文件夹”。然后从java工作目录将“JniHello.h”拷入刚打开的jniWin32工作目录。
(ii)操作:右键“头文件” | 添加... | 现有项...。选择jniWin32工作目录的“JniHello.h”。
注:此时可能出现问题“#include <jni.h>” 找不到jni.h的引用。解决方法,将jdk安装目录下的include文件夹中的“jni.h”,及当前文件夹下win32文件夹中“jni_md.h”、“jawt_md.h”,共3个文件,拷入VS2010安装目录下的“/VC/include/”文件夹中。
(iii)编辑:
a)打开“stdafx.h”文件,在末尾添加如下代码:
// ... ...
// TODO: 在此处引用程序需要的其他头文件
#include <jni.h>
#include "JniHello.h"
b),从“JniHello.h”中复制方法签名到“jniWin32.cpp”文件正文,并编写实现。如下所示。
// jniWin32.cpp : 定义 DLL 应用程序的导出函数。
//
#include "stdafx.h"
// 以下为正文
JNIEXPORT void JNICALL Java_JniHello_sayHi(JNIEnv *, jobject){
// 具体实现
printf("Hello !");
};
(ix)编译生成DLL。
操作:“ 生成 | 编译 ” 或“【Ctrl】+【F7】”(注意要选中“jniWin32.cpp”文件,否则可能看不到“编译”菜单)。 成功后,会在C++侧的jniWin32工作目录(可能不同级有两个,看顶层的目录)中的Debug下看到jniWin32.dll文件。如下图所示:
此时DLL制作完成。
5,部署dll运行*.class。
A)部署。将此DLL文件拷至Java的*.class(IDE下)同一目录下。
注:若报异常:
java.lang.UnsatisfiedLinkError: no XXX in java.library.path
即“找不到XXX在库路径下”,则需要将生成的DLL拷至系统可检测的PATH路径中。可检测PATH路径可由以下Java语句获得:
/**
* 获取系统PATH
*/
public class GetSysPath {
public static void main(String[] args) {
// 类路径
String str = System.getProperty("java.library.path");
System.out.println(str);
}
}
如笔者执行后的结果为(为方便阅读已格式化处理):
C:\Program Files\Java\jre6\bin . C:\WINDOWS\Sun\Java\bin C:\WINDOWS\system32 C:\WINDOWS C:/Program Files/Java/jre6/bin D:\kits\TortoiseSVN\bin D:\kits\MySQL\bin C:\Program Files\Microsoft SQL Server\100\Tools\Binn\ E:\tecPoints\JAVA_PATH C:\Program Files\Java\jdk1.6.0_18\bin D:\kits\apache-ant-1.8.2\bin D:\database\instantclient_11_2 D:\kits\maven3\bin D:\kits\ice\ZeroC\Ice-3.4.1\bin
注:为了方便管理,推荐一下笔者的做法。在上面库路径列表中,第10行“E:\tecPoints\JAVA_PATH”,为笔者在系统变量的“PATH”中添加的一个路径,专门用于存放打包、测试库等元件。只要将jniWin32.dll拷入此目录,即可被“System.loadLibrary("jniWin32")”查找到。
B)执行*.class。
运行:
$java JniHello
显示结果:
E:\tecPoints\jni>java JniHello
Hello !Hello, Zhao !
E:\tecPoints\jni>
其中,第2行第一个“Hello !”为DLL打印。
结语:
JNI原理很简单,从正文“一、概要”中可以一目了然。问题主要集中在DEMO部署上。