【混合编程JNI】之第二篇基础知识
上篇文章写了个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的函数。
JNI数据类型映射
基础类型
基础类型的映射基本上都是直接在原有的类型上增加了 j 前缀,这部分很简单
引用类型
引用类型分普通对象和数组对象。
普通对象也是直接j 前缀,
数组类型的规律是 j前缀 + 基础类型 + Array,很有规律
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侧正常调用函数
- 点赞
- 收藏
- 关注作者
评论(0)