天天看点

JNI 简介、基本原理

     jni是java native interface的缩写,中文为java本地调用。从java1.1开始,java native interface(jni)标准成为平台的一部分,它允许java代码和其他语言写的代码进行交互。jni一开始是为了本地已编译语言,尤其是c和c++而设计的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了。

      使用与本地已编译的代码交互,通常会丧失平台可移植性。但是,有些情况这样做是可以接受的,甚至是必须的。例如,使用一些旧的库,与硬件、进行交互,或者为了提高程序的性能。jni标准至少保证能工作在任何java 实现下。

标准的类库可能不支持你的程序所需的特性。或许你已经有了一个用其他语言写成的库或程序,而你希望在程序中使用它。

你可能需要用底层语言实现一个小型的时间敏感代码,比如汇编,然后在你的程序中调用这些功能。

      以下是具体步骤:

 编写带有native声明的方法的类

·使用命令编译所编写的java类,然后使用javah + java类名生成扩展名为h的头文件

·使用c/c++实现本地方法

·将c/c++编写的文件生成

·完成

示例:

helloworld.java:

package com.magc.jni;

      public class helloworld {

    static {

        system.loadlibrary("hello");

    }

    public     native void displayhello();

    /**

     * @param args

     */

    public static void main(string[] args) {

        new helloworld().displayhello();

}

进入src目录下,编译该java类,

命令:javac ./com/magc/jni/helloworld.java

在该helloworld.java所在目录下生成helloworld.class

然后使用javah生成头文件,

命令:javah -jni com.magc.jni.helloworld

在当前目录下生成com_magc_jni_helloworld.h头文件,此文件供c、c++程序来引用并实现其中的函数

       helloworld.h:

/* do not edit this file - it is machine generated */

#include <jni.h>

 /* header for class com_magc_jni_helloworld */

#ifndef _included_com_magc_jni_helloworld

#define _included_com_magc_jni_helloworld

#ifdef __cplusplus

extern "c" {

#endif

/*

 * class:     com_magc_jni_helloworld

 * method:    displayhello

 * signature: ()v

 */

jniexport void jnicall java_com_magc_jni_helloworld_displayhello

  (jnienv *, jobject);

注:1)、此头文件是不需要用户编译的,直接供其它c、c++程序引用。

     2)、此头文件中的java_com_magc_jni_helloworld_displayhello(jnienv *, jobject)方法,是将来与动态链接库交互的接口,并需要名字保持一致。

  jni_helloworldimpl.cpp:

#include "com_magc_jni_helloworld.h"

    #include <stdio.h>

(jnienv *env, jobject obj)

{

    printf("from jni_helloworldimpl.cpp :");

    printf("hello world ! \n");

    return;

此c++文件实现了上述头文件中的函数,注意方法函数名要保持一致。

编译生成动态库libhello.so,

JNI 简介、基本原理
JNI 简介、基本原理

总结了一下,jni一般有以下一些应用场景

1.高性能 ,在一些情况下因为处理运算量非常大,为了获取高性能,直接使用java是不能胜任的,如:一些图形的处理

2.调用一些硬件的驱动或者一些软件的驱动,比如调用一些外部系统接口的驱动,如:读卡器的驱动,oci驱动

3.需要使用大内存,远远超过jvm所能分配的内存,如:进程内cache

4.调用c或者操作系统提供的服务,如:java调用搜索服务,其中搜索是由c/c++实现的,不过这个一般可以设计成更加通用的方式,比如soa的方式

所有这些场景的前提是牺牲了java代码的可移植性,不同的os,甚至版本都需要写不同版本的native实现

经测试jni实现方法比普通java方法快13~15倍。

参考:

如有问题请留言,转载注明出处。