JNI 详细介绍

一 介绍 

java调⽤c++,c++代码可以通过JNIEnv执行java代码。

安卓NDK 已经对JNI环境进行了集成,我们可以通过android studio来快速搭建一个项目。

二 项目搭建

打开android studio 创建工程,创建工程选择模板Native C++

 三 模板格式介绍

生成的模板java类如下

public class MainActivity extends AppCompatActivity {// Used to load the 'jnidemo' library on application startup.static {System.loadLibrary("jnidemo");}private ActivityMainBinding binding;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);binding = ActivityMainBinding.inflate(getLayoutInflater());setContentView(binding.getRoot());// Example of a call to a native methodTextView tv = binding.sampleText;tv.setText(stringFromJNI());}/**这个方法的实现在c++测*/public native String stringFromJNI();
}

native 标记的方法没有方法体,表示在c++测实现,

对应c++测的代码如下:

extern "C"   下⾯的⽅法采⽤C的编译⽅式
JNIEXPORT // JNIEXPORT 关键字 标记该⽅法可以被外部调⽤
jstring // 返回值类型 对应 java 测的 String
JNICALL // 关键字 jni call 约束函数⼊栈顺序,和堆栈内存清理规则
Java_com_example_jnidemo_MainActivity_stringFromJNI(JNIEnv* env,jobject /* this */) {std::string hello = "Hello from C++";return env->NewStringUTF(hello.c_str());
}

那长串的名字

Java_com_example_jnidemo_MainActivity_stringFromJNI

红色为包名,绿色为类名,蓝色为方法名。

JNIEnv是c++ 和java沟通的桥梁,env就代表了java环境

四 签名和类型

你们肯定很懵,下面的表是什么,先不管它,请先硬着往下看

java类型对应在c++代码处的类型:

 

typedef void* jobject;  /*对应任何Java对象,通常对应⼀个类的实例*
typedef jobject jclass;  /*对应Java类对象,⽐如Student类*/
typedef jobject jstring;  /*java.lang.String*/
typedef jobject jarray;   /*数组*/typedef jarray jobjectArray; /*任何对象的数组*/
typedef jarray jbooleanArray; /*boolean []*/
typedef jarray jbyteArray;  /*byte []*/
typedef jarray jcharArray; /*char []*/
typedef jarray jshortArray; /*short []*/
typedef jarray jintArray;  /*int []*/
typedef jarray jlongArray; /*long []*/
typedef jarray jfloatArray; /*float []*/
typedef jarray jdoubleArray; /*double []*/
typedef jobject jthrowable; /*java.lang.Throwable*/
typedef jobject jweak;      /**/

五 函数调用

java 直接调用native 的方法,会执行c++处的实现,c++也可以通过env调用java处的代码。

c++侧执⾏java⽅法

hello,word 

便于理解我java和c++ 代码放在了一块展示,请小白对比看

//java 处代码
public void hello(){System.out.println("hello,word!");
}
public native void runHello();// c++ 处代码
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_fuc_TestMain_runHello(JNIEnv *env, jobject thiz)// env是和java沟通的桥梁// thiz代表 java对象this, 谁调用native,那么thiz就是那个对象的thiz  // 比如 A.runHello(),那么thiz就是A对象// 获得Class 对象 jclass thisClass= env->GetObjectClass(thiz);// 根据方法名字、参数、返回类型; 获得 hello ⽅法id,// "hello" 为方法名字// 后面的()V  () 代表参数为空,V代表返回值为void jmethodID helloMethodID= env->GetMethodID(thisClass,"hello", "()V");// 根据方法id来执行方法,执行 thiz的hello方法env->CallVoidMethod(thiz,helloMethodID);
}

c++执行java 测的有参函数

// java 处代码
private int add(int a,int b){return a+b;
}
public native int runAdd(int a,int b);// c++ 处代码
extern "C"
JNIEXPORT jint JNICALL
Java_com_example_myapplication_fuc_TestMain_runAdd(JNIEnv *env, jobject thiz, jint a,jint b){// 获得Class 对象// jclass 表示java Class 类型jclass thisClass= env->GetObjectClass(thiz);// 获取add ⽅法id// (II)I 表示参数类型 第一个I表示第一个参数 类型为int类型,第二个I表示第二个参数为int类型,// 括号外面那个I 表示返回类型为I即int// 方法签名对应请看 上文第四节jmethodID addMethodID= env->GetMethodID(thisClass,"add", "(II)I");// 运⾏ add(a,b) // jint 对应java int类型jint result= env->CallIntMethod(thiz,addMethodID,a,b);return result;
}// test 处的测试方法
// 测试 add
@Test
public void testAdd(){// 实际上运行c++处的实现,c++处的实现又去调用java的 add方法int result = testMain.runAdd(4, 2); System.out.println("addResult:"+result);
}

这么一看是不是非常像反射调用执行方法,我们对比一下反射学习:

// 反射执⾏
@Test
public void load() throws Exception{// 获得class对象Class<? extends TestMain> aClass = testMain.getClass();// 获得add⽅法Method add = aClass.getDeclaredMethod("add", int.class, int.class);// 设置可⻅性add.setAccessible(true);// 运⾏add⽅法Object invoke = add.invoke(testMain,2, 4);System.out.println("执⾏结果:"+invoke);
}

是的,非常类似,都是先获得class对象,然后获得方法,再执行方法。

修改成员属性值

在c++处修改 java对象的成员变量

// java 处
public  int age;public int getAge() {return age;
}
public native void setAge();// c++ 处
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_fuc_TestMain_setAge(JNIEnv *env, jobject thiz) {// 获得class对象jclass thisClass= env->GetObjectClass(thiz);// 获得 属性IDjfieldID ageID=env->GetFieldID(thisClass,"age", "I");// 执⾏修改env->SetIntField(thiz,ageID,35);
}// test
@Test
public void testSetAge(){System.out.println("修改前:"+testMain.getAge());testMain.setAge();System.out.println("修改后:"+testMain.getAge());
}

创建对象

在c++侧创建⼀个List数组,并向它添加"A","B"元素

// java
public native List<String> getStringArray();// C++
extern "C"
JNIEXPORT jobject JNICALL
Java_com_example_myapplication_fuc_TestMain_getStringArray(JNIEnv *env, jobject){// 获得ArrayList Class 对象jclass listClass= env->FindClass("java/util/ArrayList");// 获得ArrayList 构造⽅法id// 构造方法签名统一为 <init>jmethodID initMethodID= env->GetMethodID(listClass,"<init>", "()V");// 创建 ArrayList 对象,相当于在java处那么 new了一个对象jobject list= env->NewObject(listClass,initMethodID);// 获得add ⽅法idjmethodID addMethodID= env->GetMethodID(listClass,"add", "(ILjava/lang/Object;)V");// 创建 A 和 Bjstring A= env->NewStringUTF("A");jstring B= env->NewStringUTF("B");// 添加元素env->CallVoidMethod(list,addMethodID,0,A);env->CallVoidMethod(list,addMethodID,1,B);// 释放本地引⽤// 只是释放c++ 测的引用,并没有删除 java那么对应的对象env->DeleteLocalRef(A);env->DeleteLocalRef(B);return list;
}// 在 c++ 的实现相当于执⾏了如下java 代码
ArrayList<Object> list = new ArrayList<>();
list.add(0,"A");
list.add(1,"B");

创建全局引⽤

1. 全局引⽤:全局引⽤在整个Java虚拟机中都有效,只要它们还在被使⽤,它们就不会被垃圾回收。全局引⽤在JNI代码结束时必须显式删除。

jobject globalRef = env->NewGlobalRef(localRef);// ...
env->DeleteGlobalRef(globalRef);

2. 本地引⽤:本地引⽤只在单个JNI调⽤期间有效。当JNI⽅法返回时,所有的本地引⽤都会⾃动被删除。(保险起⻅需要⼿动删除)

jobject localRef = env->NewLocalRef(tem);// ...
env->DeleteLocalRef(localRef);

异常处理

在JNI中,异常处理有点不⼀样,当在c++调⽤java⽅法抛出异常时候,函数不会直接捕获异常,异常会直接挂起,需要⼿动处理
• ExceptionCheck :这个⽅法⽤于检查是否有未处理的异常。它返回⼀个布尔值,如果存在未
处理的异常,则返回 true ,否则返回 false 。
• ExceptionOccurred :这个⽅法⽤于检查是否有异常发⽣。它返回⼀个指向异常对象的引⽤,
如果没有异常发⽣,则返回 nullptr 。
应该在执⾏⽅法时候都做⼀个异常处理,防⽌程序崩溃

 

// java
// 抛出运⾏异常
public int throwError(){return 1/0;
}public native void tryError();// c++
// 抛出异常
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_fuc_TestMain_tryError(JNIEnv *env, jobject thiz){// 执⾏异常代码jclass thisClass= env->GetObjectClass(thiz);jmethodID throwErrorMethodId= env->GetMethodID(thisClass,"throwError","()I");// 异常jint result= env->CallIntMethod(thiz,throwErrorMethodId);// 是否有异常if(env->ExceptionOccurred()!= nullptr){// 输出异常信息env->ExceptionDescribe();// 清除挂起的异常env->ExceptionClear();// 创建 RuntimeException 对象jclass runErrorClass = env->FindClass("java/lang/RuntimeException");// 抛出异常 消息"ERROR!"env->ThrowNew(runErrorClass,"ERROR!");return;}
}// 测试
@Test
public void testError(){try {testMain.tryError();}catch (Exception e){System.out.println("有异常");e.printStackTrace();}
}

六 总结



c++ 调⽤java⽅法
        1、获得class对象
        2、获得对象中的⽅法id
        3、执⾏⽅法


c++创建java对象
        1、获得class对象
        2、获得构造⽅法id
        3、执⾏构造⽅法


异常处理流程
        c++层调⽤执⾏java对象⽅法
        异常处理




如果认为对你有帮助,欢迎点赞收藏 

如果认为对你有帮助,欢迎点赞收藏 

如果认为对你有帮助,欢迎点赞收藏 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1535669.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

基于Python实现的一个电影知识库QA系统

1. 实现效果 1. 图形展示 这是使用echarts.js 来实现的自定义页面的图谱展示&#xff0c;当然还有其他的库也能实现类似的效果&#xff0c;这里看各位的选择。 这里我在每个实体之间都实现了双层关系的绑定&#xff0c;这对于后面实现检索会有点帮助 2. 实体搜索展示 这里…

数字孪生卷进了天气预报行业

在视频中&#xff0c;上一秒主持人还在大屏幕前正常播报天气。下一秒&#xff0c;场景切换&#xff0c;主持人走到旁边&#xff0c;演播室边上呈现出狂风骤雨的街道&#xff0c;随着播报&#xff0c;一棵被台风吹倒的树“砸进”演播室&#xff0c;营造出一种惊险的感觉&#xf…

Java | Leetcode Java题解之第405题数字转换为十六进制数

题目&#xff1a; 题解&#xff1a; class Solution {public String toHex(int num) {if (num 0) {return "0";}StringBuffer sb new StringBuffer();for (int i 7; i > 0; i --) {int val (num >> (4 * i)) & 0xf;if (sb.length() > 0 || val …

Java | Leetcode Java题解之第406题根据身高重建队列

题目&#xff1a; 题解&#xff1a; class Solution {public int[][] reconstructQueue(int[][] people) {Arrays.sort(people, new Comparator<int[]>() {public int compare(int[] person1, int[] person2) {if (person1[0] ! person2[0]) {return person2[0] - perso…

驾驶员注意力分神状态检测系统源码分享

驾驶员注意力分神状态检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of …

springboot医院预约挂号系统 ---附源码73444

目录 1 绪论 1.1 研究背景 1.2研究意义 1.3论文结构与章节安排 2 医院预约挂号系统系统分析 2.1 可行性分析 2.2 系统功能分析 2.3 系统用例分析 2.4 系统流程分析 2.5本章小结 3 医院预约挂号系统总体设计 3.1 系统功能模块设计 3.2 数据库设计 3.4本章小结 4 医…

【文件系统】软硬链接

目录 1. 汇总 ext2 文件系统2. 文件名 与 inode 的关联3. 软硬链接3.1 理解硬链接3.2 理解软链接3.3 软硬链接的应用场景 1. 汇总 ext2 文件系统 新建文件 一个文件一定是在某个路径下创建的&#xff0c;有了路径&#xff0c;就能够知道该新建文件所在分区&#xff0c;然后再查…

在线查看 Android 系统源代码 AOSPXRef and AndroidXRef

在线查看 Android 系统源代码 AOSPXRef and AndroidXRef 1. AOSPXRef1.1. http://aospxref.com/android-14.0.0_r2/1.2. build/envsetup.sh 2. AndroidXRef2.1. http://androidxref.com/9.0.0_r3/2.2. build/envsetup.sh 3. HELLO AndroidReferences 1. AOSPXRef http://aospx…

JAVA基础面试题总结(十五)——设计模式

面试专题-设计模式 前言 在平时的开发中&#xff0c;涉及到设计模式的有两块内容&#xff0c;第一个是我们平时使用的框架&#xff08;比如spring、mybatis等&#xff09;&#xff0c;第二个是我们自己开发业务使用的设计模式。 面试官一般比较关心的是你在开发过程中&#…

浮动元素详解

浮动元素 代码实现&#xff1a; <!DOCTYPE html> <html><head><meta charset"utf-8"><title>浮动元素</title><style>#container1 {width: 400px;height: 50px;background-color: lightgrey;border: 1px solid;}#contai…

828华为云征文|华为云Flexus云服务器X实例之openEuler系统下dufs文件服务器

828华为云征文&#xff5c;华为云Flexus云服务器X实例之openEuler系统下dufs文件服务器 一、Flexus云服务器X实例介绍1.1 Flexus云服务器X实例简介1.2 Flexus云服务器X实例特点1.3 Flexus云服务器X实例使用场景 二、dufs介绍2.1 dufs简介2.2 dufs特点2.3 使用场景 三、本次实践…

学习整理vue前端框架项目目录结构的含义

学习整理vue前端框架项目目录结构的含义 1、目录结构2、结构含义 1、目录结构 2、结构含义

大模型大侦探-一次丝滑的探图记录

文章目录 缘起调查深入确认总结 缘起 最近找到了我的一台老笔记本电脑&#xff0c;竟然还能开机&#xff0c;是XP的。里面有一个桌面&#xff0c;叫做panMilk: 这太美了&#xff0c;但这是哪里&#xff1f;这个问题在20年前就困扰了我&#xff0c;不得答案。这些年学校、公司的…

CorrMatch复现

复现结果–Full&#xff1a;81.78327847863439&#xff0c;成功 U2PL’s splits计算量太大&#xff0c;不建议复现

美团图床设置教程

大厂图床&#xff0c;CDN加速 项目地址&#xff1a;https://github.com/woniu336/mt-img 使用方法 在mt.php填上你的token即可&#xff0c;然后打开index.html上传图片 获取token方法 注册https://czz.meituan.com/发布视频&#xff0c;上传封面&#xff0c;注意在上传封面后…

2024年汉字小达人区级自由报名备考冲刺:往年真题练一练

2024年第十一届汉字小达人的区级活动的时间9月25-30日正式开赛&#xff0c;还有不到两周时间。 最后的冲刺时间&#xff0c;可以利用接下来的三天中秋假期做几套模拟题&#xff0c;熟悉汉字小达人的比赛形式、考察方式&#xff0c;尤其是把2024年的模拟题做做熟&#xff0c;查…

2、HDFS编程实践

目录 1、Hadoop三种Shell方式(1)目录操作1、查看目录2、创建目录3、删除目录 &#xff08;2&#xff09;文件操作1、创建文件2、上传文件3、下载文件4、拷贝文件 2、利用Web界面管理HDFS3、利用Java API 与 HDFS 进行交互&#xff08;1&#xff09;安装eclipse包&#xff08;2&…

CH1-1 引论

一、参考教材 清华大学出版社《数值分析》李庆扬 王能超 易大义 编 数值分析 机械工业出版社 Numerical Analysis David Kincaid Ward Cheney 著 二、课程背景 所学内容在数学学科体系里的位置: 所学内容: 计算数学是广泛的研究框架,数值分析(教材名)是理论研究,计算…

Python基础知识学习(2)

一&#xff0c;分支条件判断语句 在python中&#xff0c;分支条件语句如下&#xff1a; 1&#xff0c;判断条件&#xff1a;if exception: 2&#xff0c;接着判断的语句为&#xff1a;elif exception: 3&#xff0c;最后的条件为&#xff1a;else: 4&#xff0c;通过缩进来表示…

在线查看 Android 系统源代码 Git repositories on android

在线查看 Android 系统源代码 Git repositories on android 1. Git repositories on android1.1. Android Make Build System1.2. Android Open Source Project Code Review References 1. Git repositories on android https://android.googlesource.com/ 1.1. Android Make …