JNI概述
JNI 是Java Native Interface的缩写,中文译为“Java本地调用”。通常使用JNI技术可以做到以下两点:
(1)Java程序中的函数可以调用Native语言函数,Native函数一般指的是C/C ++编写的函数;
(2)Native程序中的函数可以调用Java层的函数,也就是说在C/C++程序中可以调用Java层函数。
当然任何事物都有两面性,JNI也不例外,使用JNI主要缺点有以下两点:
(1)使用JNI技术将导致Java Application不能跨平台。如果要移植到别的平台上,那么Native代码就要重新进行编写;
(2)Java是强类型的语言,而C/C++不是,因此在编写JNI的时候要非常谨慎。
JNI--Hello World
我们在学习任何一门语言技术时,首先编写的应该是简单的“ Hello World ”,那么接下来就给大家介绍怎样使用JNI技术来实现Hello World。
(1)首先在Java类中声明一个native的方法
在eclipse中新建一个NativeDemo工程,类名为TestNative,具体代码如下所示:
package com.jony.nativetest;
public class TestNative {
public native void sayHello();
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
}
}
(2)使用Javah命令生成包含native方法定义的C/C++头文件;
在Java的安装路径(D:\Java\jdk1.6.0_24\bin)中大家可以看到很多可执行文件,其中包含我们常用的java、javac、javah等命令。首先,我们可以简单查看一下javah命令的使用方法,在命令行中输入 javah -help 查看命令参数和使用方法,如图所示:
接下来首先将我们编写的TestNative.java文件编译成class文件,在我本地代码中对应的路径为:E:\Workspaces\android\NativeDemo\bin,具体如图所示:
在命令提示框中输入:cd E:\Workspaces\android\NativeDemo\bin 和 E: 进入到对应的文件目录,如图所示:
最后在命令提示框中输入 javah com.jony.nativetest.TestNative 命令生成.h头文件,如入所示:
执行完以上命令后,在路径E:\Workspaces\android\NativeDemo\bin下就能查看生成的.h头文件。生成代码如下(com_jony_nativetest_TestNative.h):
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_jony_nativetest_TestNative */
#ifndef _Included_com_jony_nativetest_TestNative
#define _Included_com_jony_nativetest_TestNative
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_jony_nativetest_TestNative
* Method: sayHello
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_jony_nativetest_TestNative_sayHello
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
(3)按照生成的C/C++头文件来写C/C++源文件
首先,在VC++编译器中创建一个Win32 Dynamic-Link Library工程,工程名为NativeCode02,将之前生成的头文件(com_jony_nativetest_TestNative.h)拷贝到NativeCode02项目的根目录。
接下来创建source.cpp文件,目录结构如图所示:
C++代码比较简单,具体代码如上图所示。
(4)将C/C++源文件编译成动态链接库(DLL--可执行的二进制代码)
在进行编译(Ctrl + F5)源文件时,出现以下异常:
--------------------Configuration: NativeCode02 - Win32 Debug--------------------
Compiling...
source.cpp
i:\archive_software\c&c++\vc6.0完整绿色版\myprojects\nativecode02\com_jony_nativetest_testnative.h(2) : fatal error C1083: Cannot open include file: 'jni.h': No such file or directory
执行 cl.exe 时出错.
NativeCode02.dll - 1 error(s), 0 warning(s)
该异常表明在编译的时候没有找到jni.h头文件。在Java的JDK中提供了该头文件,因此我们可以Java安装路径(D:\Java\jdk1.6.0_24\include)找到该头文件,将其拷贝到NativeCode01工程的Header Files目录下
(备注:因为jni.h头文件已经拷贝到本地,因此引用的时候应该将<>替换成" ")再次进行编译(Crtl + F5),出现以下异常:
--------------------Configuration: NativeCode02 - Win32 Debug--------------------
Compiling...
source.cpp
i:\archive_software\c&c++\vc6.0完整绿色版\myprojects\nativecode02\jni.h(27) : fatal error C1083: Cannot open include file: 'jni_md.h': No such file or directory
执行 cl.exe 时出错.
NativeCode02.dll - 1 error(s), 0 warning(s)
该异常也非常容易理解,缺少jni_md.h头文件,同样在Java的安装路径()中找到该头文件并将其拷贝到Header Files目录下,再次进行编译:
--------------------Configuration: NativeCode02 - Win32 Debug--------------------
Compiling...
source.cpp
Linking...
Creating library Debug/NativeCode02.lib and object Debug/NativeCode02.exp
NativeCode02.dll - 0 error(s), 0 warning(s)
OK,编译成功,在工程项目的Debug目录中可以看到我们编译成功的NativeCode02.dll文件。
(5)将动态链接库路径保存在path路径下,这样在Java代码中就可以直接调用该动态链接库(DLL)
具体步骤省略
(6)编写Java层代码
当动态链接库编译成功后,我们就可以在Java层调用该动态链接库了,代码比较简单,直接上代码:
package com.jony.nativetest;
public class TestNative {
public native void sayHello();
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
System.loadLibrary("NativeCode02");// 加载动态链接库
TestNative testNative = new TestNative();
testNative.sayHello();//调用naive方法
}
}
OK,大功告成,JNI--Hello World至此已经实现,接下来的博客将给大家深入介绍JNI的使用方式,技术源于分享,大家共同进步……