美文网首页
一、JNI基础

一、JNI基础

作者: ChiangCMBA | 来源:发表于2018-04-05 17:04 被阅读0次

一、JNI开发的步骤;

二、静态库和动态库的区别;

三、JNIEnv 是什么?

四、JNI基本数据类型;

五、常用命令:javah, javap;

六、JNI调用Java类对象的字段、非静态方法、静态方法、构造方法;

七、JNI类型签名

==========================================
一、JNI开发的步骤
1.编写native 方法;
2.javah 命令,生成.h 文件(或者自己手写);
java_类的全名_方法名
3.复制.h 头文件到cpp 工程;
4.复制jni.h 和jni_md.h;
5.实现.h 头文件中的声明函数;
6.生成一个.dll /.so动态库;(要配置指定支持的cpu架构类型)
7.在java中加载动态库;
8.调用native函数;

二、静态库和动态库的区别;
函数库分为静态库和动态库两种。
1.静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。
2.动态库在程序编译时并不会被连接到目标代码中,而是在程序运行时才被载入,因此在程序运行时还需要动态库存在。

1、 静态函数库
这类库的名字一般是libxxx.a;利用静态函数库编译成的文件比较大,因为整个 函数库的所有数据都会被整合进目标代码中,他的优点就显而易见了,即编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进去了。当然这也会成为他的缺点,因为如果静态函数库改变了,那么你的程序必须重新编译。

2、 动态函数库
这类库的名字一般是libxxx.so;相对于静态函数库,动态函数库在编译的时候 并没有被编译进目标代码中,你的程序执行到相关函数时才调用该函数库里的相应函数,因此动态函数库所产生的可执行文件比较小。由于函数库没有被整合进你的程序,而是程序运行时动态的申请并调用,所以程序的运行环境中必须提供相应的库。动态函数库的改变并不影响你的程序,所以动态函数库的升级比较方便。

三、JNIEnv 是什么?
JNIEnv是一个与线程相关的代表JNI环境的结构体。
JavaVM和JNIEnv的关系:
1、调用JavaVM的AttachCurrentThread函数,就可得到这个线程的JNIEnv结构体。这样可以在后台线程中回调Java函数。
2、在后台线程退出前,需要调用JavaVM的DetachCurrentThread函数来释放对应资源。

/*
 * JNI Native Method Interface.
 */
struct JNINativeInterface_;
struct JNIEnv_;

#ifdef __cplusplus
typedef JNIEnv_ JNIEnv;
#else
typedef const struct JNINativeInterface_ *JNIEnv;
#endif

struct JNINativeInterface_ {
    void *reserved0;
    void *reserved1;
    void *reserved2;
    void *reserved3;
    jint (JNICALL *GetVersion)(JNIEnv *env);
    jclass (JNICALL *DefineClass)
      (JNIEnv *env, const char *name, jobject loader, const jbyte *buf,
       jsize len);
    jclass (JNICALL *FindClass)
      (JNIEnv *env, const char *name);
......... 

}; 

struct JNIEnv_ {
    const struct JNINativeInterface_ *functions;

#ifdef __cplusplus
    jint GetVersion() {
        return functions->GetVersion(this);
    }

    jclass DefineClass(const char *name, jobject loader, const jbyte *buf, jsize len) {
        return functions->DefineClass(this, name, loader, buf, len);
    }

    jclass FindClass(const char *name) {
            return functions->FindClass(this, name);
    }
    .........
#endif /* __cplusplus */

};

/*
 * We use inlined functions for C++ so that programmers can write:
 *    env->FindClass("java/lang/String")
 * in C++ rather than:
 *    (*env)->FindClass(env, "java/lang/String")in C.
 */

==================================
* * *
==================================

/*
 * JNI Invocation Interface.
 */

struct JNIInvokeInterface_;
struct JavaVM_;

#ifdef __cplusplus
        typedef JavaVM_ JavaVM;
#else
        typedef const struct JNIInvokeInterface_ *JavaVM;
#endif

struct JNIInvokeInterface_ {
    void *reserved0;
    void *reserved1;
    void *reserved2;

    jint (JNICALL *DestroyJavaVM)(JavaVM *vm);
    jint (JNICALL *AttachCurrentThread)(JavaVM *vm, void **penv, void *args);
    jint (JNICALL *DetachCurrentThread)(JavaVM *vm);
    jint (JNICALL *GetEnv)(JavaVM *vm, void **penv, jint version);
    jint (JNICALL *AttachCurrentThreadAsDaemon)(JavaVM *vm, void **penv, void *args);
};

struct JavaVM_ {
    const struct JNIInvokeInterface_ *functions;
#ifdef __cplusplus
    jint DestroyJavaVM() {
        return functions->DestroyJavaVM(this);
    }

    jint AttachCurrentThread(void **penv, void *args) {
        return functions->AttachCurrentThread(this, penv, args);
    }

    jint DetachCurrentThread() {
        return functions->DetachCurrentThread(this);
    }

    jint GetEnv(void **penv, jint version) {
        return functions->GetEnv(this, penv, version);
    }

    jint AttachCurrentThreadAsDaemon(void **penv, void *args) {
        return functions->AttachCurrentThreadAsDaemon(this, penv, args);
    }

#endif

};

1.为什么需要传入JNIEnv,函数执行过程中需要JNIEnv
2.C++为什么没有传入?this
3.C++只是对C的那一套进行的封装,给一个变量赋值为指针,这个变量是二级指针
C/C++中为什么有区别?

四、JNI基本数据类型;
基本数据类型转换

#ifdef HAVE_INTTYPES_H
# include <inttypes.h>      /* C99 */
typedef uint8_t         jboolean;       /* unsigned 8 bits */
typedef int8_t          jbyte;          /* signed 8 bits */
typedef uint16_t        jchar;          /* unsigned 16 bits */
typedef int16_t         jshort;         /* signed 16 bits */
typedef int32_t         jint;           /* signed 32 bits */
typedef int64_t         jlong;          /* signed 64 bits */
typedef float           jfloat;         /* 32-bit IEEE 754 */
typedef double          jdouble;        /* 64-bit IEEE 754 */
#else
typedef unsigned char   jboolean;       /* unsigned 8 bits */
typedef signed char     jbyte;          /* signed 8 bits */
typedef unsigned short  jchar;          /* unsigned 16 bits */
typedef short           jshort;         /* signed 16 bits */
typedef int             jint;           /* signed 32 bits */
typedef long long       jlong;          /* signed 64 bits */
typedef float           jfloat;         /* 32-bit IEEE 754 */
typedef double          jdouble;        /* 64-bit IEEE 754 */
#endif

五、常用命令:javah, javap
1.javah
2.javap -s -p :获取类字段和方法的签名信息
3.javap -s -p -v :可以查看类中方法的descriptor flags;

六、JNI调用Java类对象的字段、非静态方法、静态方法、构造方法

七、JNI类型签名
1、JNI函数签名信息,有参数类型和返回值类型共同组成。
2、为什么需要签名信息
因为Java支持函数重载,即可以定义同名但不同参数的函数。但仅仅根据函数名无法找到具体函数。为了解决这个问题,JNI技术中就将参数类型和返回值类型的组合作为一个函数的签名信息,有了签名信息和函数名,就能准确找到Java中的函数。

3、如何生成函数或变量的签名信息:
javap -s -p xxx

相关文章

网友评论

      本文标题:一、JNI基础

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