JNI初入(一)之Hello
一、JNI简介
JNI,即Java Native Interface,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++)。从Java1.1开始,JNI标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。
1.1 JAVA平台和系统环境(Host Environment)
系统环境代指本地操作系统环境,它有自己的本地库和CPU指令集。本地程序(Native Applications)使用C/C++这样的本地语言来编写,被编译成只能在本地系统环境下运行的二进制代码,并和本地库链接在一起。本地程序和本地库一般地会依赖于一个特定的本地系统环境。比如,一个系统下编译出来的C程序不能在另一个系统中运行。
1.2 JNI扮演的角色
JNI的强大特性使我们在使用JAVA平台的同时,还可以重用原来的本地代码。作为虚拟机实现的一部分,JNI允许JAVA和本地代码间的双向交互。

JNI可以这样与本地程序进行交互:
1、 你可以使用JNI来实现“本地方法”(native methods),并在JAVA程序中调用它们。
2、 JNI支持一个“调用接口”(invocation interface),它允许你把一个JVM嵌入到本地程序中。本地程序可以链接一个实现了JVM的本地库,然后使用“调用接口”执行JAVA语言编写的软件模块。例如,一个用C语言写的浏览器可以在一个嵌入式JVM上面执行从网上下载下来的applets
1.3 JNI的副作用
请记住,一旦使用JNI,JAVA程序就丧失了JAVA平台的两个优点:
1、 程序不再跨平台。要想跨平台,必须在不同的系统环境下重新编译本地语言部分。
2、 程序不再是绝对安全的,本地代码的不当使用可能导致整个程序崩溃。
一个通用规则是,你应该让本地方法集中在少数几个类当中。这样就降低了JAVA和C之间的耦合性。
1.4 什么场合下应该使用JNI
当你开始着手准备一个使用JNI的项目时,请确认是否还有替代方案。像上一节所提到的,应用程序使用JNI会带来一些副作用。下面给出几个方案,可以避免使用JNI的时候,达到与本地代码进行交互的效果:
1、 JAVA程序和本地程序使用TCP/IP或者IPC进行交互。
2、 当用JAVA程序连接本地数据库时,使用JDBC提供的API。
3、 JAVA程序可以使用分布式对象技术,如JAVA IDL API。
这些方案的共同点是,JAVA和C 处于不同的线程,或者不同的机器上。这样,当本地程序崩溃时,不会影响到JAVA程序。
下面这些场合中,同一进程内JNI的使用无法避免:
1、 程序当中用到了JAVA API不提供的特殊系统环境才会有的特征。而跨进程操作又不现实。
2、 你可能想访问一些己有的本地库,但又不想付出跨进程调用时的代价,如效率,内存,数据传递方面。
3、 JAVA程序当中的一部分代码对效率要求非常高,如算法计算,图形渲染等。
总之,只有当你必须在同一进程中调用本地代码时,再使用JNI。
二、快速入门
我们来实现一个简单的jni程序:java调用c++程序打印一串字:"Hello, it works!"。
步骤如下:
1.首先创建一个java类(Hello.java)声明本地方法;
1 /** 2 * Project Name:JNIProjectDemo 3 * Package Name:com.xuwei.jni.helloworld 4 * author:David 5 * Date:2016年5月22日上午11:07:09 6 * Copyright (c) 2016, xw123box@126.com All Rights Reserved. 7 * 8 */ 9 package com.xuwei.jni.hello; 10 11 /** 12 * @author David 13 * @since 2016年5月22日 上午11:07:09 14 * @version 15 * @since JDK 1.6 16 */ 17 public class Hello { 18 public native void sayHello(); 19 20 static{ 21 System.loadLibrary("assets/say_hello"); 22 } 23 24 /** 25 * @param args 26 */ 27 public static void main(String[] args) { 28 new Hello().sayHello(); 29 } 30 31 }
2.编译源文件生成Hello.class字节码。对.class文件使用javah命令来生成c头文件(com_xuwei_jni_hello_Hello.h),这个头文件包含了本地方法的函数原型;
操作如下:
java项目:

生成头文件:

3.用c&C++来写函数原型的实现并生成链接库dll文件(如果是操作系统是linux平台则是.so文件);
新建c++ win32链接库项目,别选错了。。。



(由于我的操作系统是Windows10 64位,jdk也是64位的,所以在vs中设置了x64模式)

4.使用java来调用dll文件,类文件Hello.class和本地库sayHello.dll在运行时被加载。

三、注意事项
1.用class文件生成头文件时要注意类文件是否带包名,对含包名的类文件要切换到包的上一级目录后再用javah命令生成头文件,否则报错。
显然,我用eclipse开发的java类含有包名,所以我用cmd命令切换到编译路径bin目录下,用javah -classpath . com.xuwei.jni.hello.hello成功生成头文件。
2.除了要拷贝生成的头文件外,还有在jdk目录找到jni.h,jni_md.h一并拷到c/c++项目目录下,
如图:

然后在vs中添加引用该目录下的头文件。
注意由于是在当前目录下引用,所以用#include "jni.h",不要用#include <jni.h>,后者会保存找不到头文件的,双引号表示在当前引用目录下找,尖括号表示在系统库目录(环境变量给的目录下)找头文件。
所以,com_xuwei_jni_hello_Hello.h中的jni.h引用要记得手动改下,默认生成的引用是#include <jni.h>
3.注意平台要一致,64位jdk配64位动态库,32位配32位的。
浙公网安备 33010602011771号