【混合编程JNI】之第二篇基础知识

举报
香菜聊游戏 发表于 2022/06/26 21:23:17 2022/06/26
【摘要】 上篇文章写了个hello world,大概知道JNI是什么情况,混合编程JNI之第一篇,Hello world_香菜-CSDN博客 JNI 第一篇,hello world gamwatcher.blog.csdn.net/article/det…这篇文章详细讲下JNI的一些知识点JavaVM和JNIEnv这可能是JNI编程的过程中,最常见到的两个变量了,所以先理解透了才能知道怎么编程。Jav...

上篇文章写了个hello world,大概知道JNI是什么情况,

混合编程JNI之第一篇,Hello world_香菜-CSDN博客 JNI 第一篇,hello world gamwatcher.blog.csdn.net/article/det…

这篇文章详细讲下JNI的一些知识点

JavaVM和JNIEnv

这可能是JNI编程的过程中,最常见到的两个变量了,所以先理解透了才能知道怎么编程。

JavaVM:JavaVM就是整个虚拟机的指针,一个虚拟机只有一个JavaVM指针。

JNIEnv:每个线程一个JNI的数据结构,也就是说JNIEnv 只能代表一个线程

使用JNIEnv 可以操作Java代码,执行Java脚本中的逻辑,只能在当前线程

看下官方的图,JNI的指针是什么,JNI指向了Native的函数。

image.png

JNI数据类型映射

基础类型

基础类型的映射基本上都是直接在原有的类型上增加了 j 前缀,这部分很简单

image.png

引用类型

引用类型分普通对象和数组对象。

普通对象也是直接j 前缀,

数组类型的规律是 j前缀 + 基础类型 + Array,很有规律

image.png

JNI 的方法签名

Java层的native方法与C++层的方法在名称上具有一一对应的关系,具体要求如下:

native层的方法名为:Java_(__)

其中,包名使用下划线代替点号进行分割

只有当native方法出现需要重载的时候,native层的方法名后才需要跟上参数(括号里的内容),参数的编写形式与JNI签名相关(后面会介绍)

举个例子

在Java中定义如下native方法

package org.pdool; 
class Lib {
    public static native int sum(int a,int b);
}

在c++ 中的函数签名为

JNIEXPORT jint JNICALL Java_org_pdool_Lib_sum
        (JNIEnv *, jclass, jint, jint);

工具方法 可以看到上面的方法名虽然有命名规则,但是写起来还是很麻烦,所以Java官方提供了工具javah

首先找到编译的class 文件地址,比如我的路径:D:\workspace\ba\TestJni\TestJNA\target\classes>,

打开控制台切换到当前路径

然后执行

javah -jni org.jni.JniLib

javah 是jdk 的bin目录下的exe 文件,如果控制台报没有找到命令,

检查下你jdk是否加入了环境变量 path

可以使用javah -help 查看命令帮助

执行上面的语句就会生成c++ 的头文件

#include <jni.h>
/* Header for class org_jni_JniLib */
 
#ifndef _Included_org_jni_JniLib
#define _Included_org_jni_JniLib
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     org_jni_JniLib
 * Method:    mul
 * Signature: (DD)D
 */
JNIEXPORT jdouble JNICALL Java_org_jni_JniLib_mul
  (JNIEnv *, jobject, jdouble, jdouble);
 
#ifdef __cplusplus
}
#endif
#endif

拿到C++工程,直接实现上面的头文件就可以了

动态注册

上面的是在开发的期间就决定了注册的函数,可能有些需要动态的注册函数,下面说下怎么动态的链接

主要是在C++侧动态的将函数和Java层进行链接

主要的方法是

env->RegisterNatives(clazz, methods, 1) env 是环境指针

clazz 是要绑定的方法所在class 对象

methods 是 要绑定的方法指针

/*
    该数组中 , 每个元素都是一个 JNI 的 Native 方法
    JNINativeMethod 是结构体
        typedef struct {
            const char* name;       //Java 中定义的 Native 方法名 , 注意这是一个 C 字符串
            const char* signature;  //函数签名 , 可以使用 javap 生成
            void*       fnPtr;      //C/C++ 中的 Native 函数签名
        } JNINativeMethod;
 */
static const JNINativeMethod methods[] = {
        {"dynamicRegisterJavaMethod", "()V", (void *)dynamicRegisterCMethod},
        {"dynamicRegisterJavaMethod2", "(I)I", (void *)dynamicRegisterCMethod2}
};

C++ 中访问Java的类 C++ 可能需要访问java 中的对象,或者方法,这部分其实和反射差不多,是直接操作。

首先看下方法签名

Java类型         类型签名

boolean           Z

byte                B

int                  I

char               C

short              S

long               L

float              F

double           D

void              V

数组              [类型签名,比如int[] 是[I

类                 L全限定名;,比如String, 其签名为Ljava/lang/String;(注意后面有个分号)

举个例子

public int doSomething(int index, String value,int[] arr) 对应签名:

(ILjava/util/String;[I)I

总结

写的有点累,这篇先这样,下篇继续,欢迎订阅

总结下开发JNI的顺序

在Java侧定义好方法前面 javah 生成头文件给到C++侧 C++侧实现头文件的方法 C++侧编译成dll 或者so 给到Java 侧 Java侧正常调用函数


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。