美文网首页
Java native方法以及JNI实践

Java native方法以及JNI实践

作者: 罗拙呓 | 来源:发表于2018-03-10 16:03 被阅读0次

    前言

    今天看AndFix实现时,核心方法之ReplaceMethod方法是一个native方法,之前并没有遇到过,所以在此整理记录。

    native的作用

    总而言之:native是与C++联合开发的时候用的!使用native关键字说明这个方法是原生函数,也就是这个方法是用C/C++语言实现的,并且被编译成了DLL,由java去调用。

    1. native 是用做java 和其他语言(如c++)进行协作时使用的,也就是native 后的函数的实现不是用java写的。
    2. 既然都不是java,那就别管它的源代码了,我们只需要知道这个方法已经被实现即可。
    3. native的意思就是通知操作系统, 这个函数你必须给我实现,因为我要使用。 所以native关键字的函数都是操作系统实现的, java只能调用。
    4. java是跨平台的语言,既然是跨了平台,所付出的代价就是牺牲一些对底层的控制,而java要实现对底层的控制,就需要一些其他语言的帮助,这个就是native的作用了

    JNI简介

    native方法是通过java中的JNI实现的。JNI是Java Native Interface的 缩写。从Java 1.1开始,Java Native Interface (JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。

    JNI一开始是为了本地已编译语言,尤其是C和C++而设计 的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了。

    目前java与dll交互的技术主要有3种:jni,jawin和jacob。

    目前功能性而言:jni >> jawin > jacob,其大致的结构如下图:

    jni_jawin_jacob

    windows,基于native的PE结构,windows的jvm基于native结构,Java的应用体系构建于jvm之上。jvm通过加载此jni程序间接调用目标原生函数。

    image

    JNI的生成步骤——Mac版

    1. 编写带有native声明的方法的java类,生成.java文件
    2. 使用javac命令编译所编写的java类,生成.class文件
    3. 使用javah -jni java类名生成扩展名为h的头文件,也即生成.h文件
    4. 使用C/C++(或者其他编程想语言)实现本地方法,创建.h文件的实现,也就是创建.cpp文件实现.h文件中的方法
    5. 将C/C++编写的文件生成动态连接库,生成jnilib文件

    JNI实例

    接下来我们按照上述步骤一个一个来生成JNI实例

    1.编写带有native声明的java类,HelloWorld.java

    public class HelloWorld {
        public native void sayHelloWorld(); //申明一个native方法
    
        static{
            System.loadLibrary("HelloWorldImpl"); //装入动态链接库,"HelloWorldImpl"是装入动态链接库的名称
        }
    
        public static void main(String[] args){
            HelloWorld helloWorld = new HelloWorld();
            helloWorld.sayHelloWorld();
        }
    }
    

    2.使用javac生成HelloWorld.class

    javac HelloWorld.java
    

    3.使用javah -jni java类生成扩展名为h的头文件

    javah -jni HelloWorld
    

    此处需要注意的是,我们应该在包名的根目录下执行,因为生成的文件的文件名需要引用包目录。不然就会报找不到类文件的错误

    生成com_think_jni_HelloWorld.h文件

    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class com_think_jni_HelloWorld */
    
    #ifndef _Included_com_think_jni_HelloWorld
    #define _Included_com_think_jni_HelloWorld
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     com_think_jni_HelloWorld
     * Method:    displayHelloWorld
     * Signature: ()V
     */
    JNIEXPORT void JNICALL Java_com_think_jni_HelloWorld_displayHelloWorld
      (JNIEnv *, jobject);
    
    #ifdef __cplusplus
    }
    #endif
    #endif
    
    

    这里我们可以这样理解:这个h文件相当于我们在java里面的接口,这里声明了一个 Java_HelloWorld_displayHelloWorld (JNIEnv *, jobject);方法,然后在我们的本地方法里面实现这个方法,也就是说我们在编写C/C++程序的时候所使用的方法名必须和这里的一致

    4使用C/C++实现本地方法

    创建HelloWorldImpl.cpp,代码如下所示:

    #include "jni.h"
    #include "com_think_jni_HelloWorld.h"
    #include <stdio.h>
    JNIEXPORT void JNICALL Java_com_think_jni_HelloWorld_displayHelloWorld(JNIEnv *env,jobject obj){
        printf("Hello World!\n");
        return;
    }
    

    5 将本地方法编写的文件生成动态链接库

    gcc -I/Library/Java/JavaVirtualMachines/[根据装的jdk版本来定]/Contents/Home/include/ -dynamiclib HelloWorldImpl.cpp -o libhell.jnilib
    

    但是会出现运行这个命令报错

    file not found

    我们找到这个文件在

    /Library/Java/JavaVirtualMachines/[根据安装的jdk版本来定]/Contents/Home/include/darwin/
    

    这个目录下,所以我们再链接该目录到以上命令中

    gcc -I/Library/Java/JavaVirtualMachines/jdk1.8.0_71.jdk/Contents/Home/include/ -I/Library/Java/JavaVirtualMachines/jdk1.8.0_71
    
    .jdk/Contents/Home/include/darwin/ -dynamiclib HelloWorldImpl.cpp -o libhell.jnilib
    

    最终成功生成libhell.jnilib

    6 运行可执行文件

    把上述文件放在同一个文件夹后,执行

    java HelloWorld
    

    即可看到

    image

    相关文章

      网友评论

          本文标题:Java native方法以及JNI实践

          本文链接:https://www.haomeiwen.com/subject/uqhbfftx.html