android底层开发学习笔记五(JNI机制上)

一、JNI介绍
    ·JNI(Java Native Interface)是一种编程框架,允许 Java 代码与用其他编程语言(如 C 或 C++)编写的代码进行交互。JNI 是 Java 语言的一个重要特性,它使得 Java 程序能够调用和被 C/C++ 程序调用,从而充分利用 Java 的跨平台特性和 C/C++ 的高性能特性。
    ·JNI 的主要用途
        1、访问本地资源:访问操作系统级别的资源,如文件系统、网络接口等。
        2、调用高性能代码:调用用 C/C++ 编写的高性能代码,如数学计算、图形处理等。
        3、与现有系统集成:与现有的 C/C++ 库或系统进行集成,避免重新编写代码。
        4、访问硬件设备:直接访问硬件设备,如摄像头、传感器等。

    ·JNI 允许 Java 代码调用本地方法(用 C/C++ 编写的函数),并允许本地代码访问 Java 对象和调用 Java 方法。JNI 的工作原理可以分为以下几个步骤:
        1、声明本地方法:在 Java 类中声明本地方法。
        2、生成头文件:使用 javac 工具生成 JNI 头文件。
        3、实现本地方法:在 C/C++ 中实现本地方法。
        4、编译本地代码:将 C/C++ 代码编译为共享库(如 .dll、.so 文件)。
        5、加载共享库:在 Java 程序中加载共享库并调用本地方法。

二、java中声明的本地接口转换成jni头文件中声明的函数
    ·为什么要转换
        1、数据类型不匹配问题:jave的数据类型占用空间大小,和c语言数据类型占用空间大小不一样,比如Int类型,无论什么平台都是4字节,而在c语言中,32位平台占用4字节,64位平台占用8字节

        2、因为java中有重载和重写,导致java中的函数和c语言中的函数不匹配的问题
            重载:方法名相同,参数列表不同
            重写:方法名相同,参数列表也相同
            对于重载,java如果直接根据函数名调用c实现的接口,可能会存在参数不匹配的问题,因为还需要根据参数来调用c实现的接口


    ·数据类型转换
        java数据类型转换成jni类型


    ·JAVA方法转换成JNI签名步骤
        方法转换成签名(jni),为了给方法加标签,使得重载函数签名后能唯一对应c语言实现的接口
        1、参数,返回值转换成签名
                例子:
                    java:   init test(int a, int b)
                    jni数据类型转换:I test(I a, I b)
                    java:   init test(int a, int b[])
                    jni数据类型转换:I test(I a, [I b)

        2、整个方法转换成签名
            例子1:
                java:   init test(int a, int b[])
                jni数据类型转换:I test(I a, [I b)
                签名:(I[I)I(标签,标签添加到函数名之后,组合一起使得java方法和c中函数一一对应)

            例子2:
                string test(int a, string b[])
                去掉方法名:string (int a, string b[])
                jni数据类型转换:(I[Ljava/long/string)Ljava/long/string;

三 、java方法调用c函数接口的步骤(JNI的静态注册)
    1、标记方法:在方法名前加native标识,通知虚拟机DVM该方法不在java中实现,而是在c中实现
    2、使用system.loadlibrary函数
        system.loadlibrary“库名”,在c库中根据库名找到对应的库,在库中找到方法对应的c语言实现函数
        库是c语言实现的,编译成库名为 libxxx.so的库

四、java方法调用c函数接口操作示例
    1、准备工具:安装JDK
        javc命令,编译java源码,将.java文件编译成.class文件
        javah命令,将.class文件生成jni头文件

    2、创建一个java源码
        1)声明本地方法:在 Java 类中声明本地方法
        2)system.loadlibrary加载本地库代码
        public class HelloWorld {
              static {   //static是静态代码块,类加载的时候只执行一次
                    System.loadLibrary("helloworld");
                }
                public native void hello(); (hello是HelloWorld 类中的一个方法)
                 public static void main(String[] args) {   
                      new HelloWorld().hello();   
                 }
            }

    3. 生成头文件:使用 javac 工具生成 JNI 头文件
        1)编译:javac  HelloWorld.java
        2)生成JNI头文件javah -jni HelloWorld
        将生成一个名为 HelloWorld.h 的头文件。这就是JNI 头文件,包含了c中要实现的代码


    4. 实现本地方法:在 C 中实现以上jni中声明的本地要实现的方法
        #include 
        #include 
        #include "HelloWorld.h"  (jni头文件)
        JNIEXPORT void JNICALL Java_HelloWorld_hello(JNIEnv *env, jobject obj) {
            printf("Hello from C!\n");
        }

    5. 编译本地代码:将 C 代码编译为共享库:
        // 在 Linux 上
        gcc -shared -fpic -o libhelloworld.so -I${JAVA_HOME}/include(jni.h的目录) -I${JAVA_HOME}/include/linux HelloWorld.c
        // 在 Windows 上
        cl /I"%JAVA_HOME%\include" /I"%JAVA_HOME%\include\win32" /LD HelloWorld.c /FeHelloWorld.dll

    6. 加载共享库,运行 Java 程序:
        export LD_LIBRARY_PATH=.
        java HelloWorld

五、JNI的动态注册
    1、回顾静态注册
        1)实现原理:根据函数名来建立java方法和JNI函数间的一对应关系
        2)实现过程
            编写java代码
            编译java代码,生成.class
            通过javah,利用.class文件生成JNI的.h文件(生成后的JNI头文件包含了java函数在JNI层的声明)
            使用.c文件实现JNI层声明的函数


    2、动态注册
        1)实现原理:直接告诉native函数其在JNI中对应函数的指针(Jni_onload);
        2)实现过程
            1、利用结构体JNINativeMethod保存Java Native函数和JNI函数的对
            2、在一个JNINativeMethod数组中保存所有native函数和JNI函数的对应关系;
            3、在Java中通过System. loadLibrary加载完JNI动态库之后,调用JNI_OnLoad函数,开始动态注册;
            4、JNI_OnLoad中会调用RegisterNatives函数进行本地方法注册;
    3、动态注册实现步骤:
        1)java实现(同静态注册)
            native声明本地函数
            system.loadlibrary()加载本地库

        2)c实现(不同于静态注册)
            实现Jni_onload函数

        3)java如何调用c库中的Jni_onload函数,或者c库中的Jni_onload函数怎么知道是哪个类调用了Jni_onload函数
            获取JVM,Jni_onload(jvm),安卓系统传参获取
            获取类:通过JVM虚拟机的env指针变量的findclass方法找到类,关联c代码和java的类(一个类对应一个java源码)
            本地方法映射到,关联java类的方法和c语言代码中的函数,使用结构体JNINativeMethod

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值