NDK编程Java如何保存C或C++对象

2024-08-22 15:32
文章标签 java c++ 保存 对象 编程 ndk

本文主要是介绍NDK编程Java如何保存C或C++对象,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

最近有个想进阶Android,学习NDK编程的小伙伴问我说看了不少网上的视频教程,大多数的主题都是讲JNI的方法签名、JNI线程绑定、JNI调用Java方法等主要的内容。
自己在练习的过程中发现如果需要重复利用一个C或者C++的对象时就不知道怎么处理了。其实这就是Java对象如何保存Native对象的一个问题而已。

听了这个朋友的疑问,我翻了下网上关于NDK的视频教程,确实是很多教程都没有介绍Java对象如何复用一个Native对象。但是这又是一个在NDK实战中必然会碰到的一个关键点。
有道是老师带入门,修行在自身,这句话是很在理的。在这个信息爆炸的年代,你与知识的距离就是一跟网线的距离,那么如何拉开大家的距离呢?或许这个时候就看谁的自学自研能力,甚至是
无师自通的拓荒能力更胜一筹了。

别人是怎么做的

虽然说不知道怎么做,但是Android官方的人肯定会啊,知名的C或者C++开源项目肯定也会涉及到这个问题啊。偷偷喵一下别人怎么做的不就可以了吗?
暗中偷学你的九阳神功

安卓经常使用的一个类Bitmap,我们看看它是怎么处理的:

public final class Bitmap implements Parcelable {private static final String TAG = "Bitmap";/*** Indicates that the bitmap was created for an unknown pixel density.** @see Bitmap#getDensity()* @see Bitmap#setDensity(int)*/public static final int DENSITY_NONE = 0;// Estimated size of the Bitmap native allocation, not including// pixel data.private static final long NATIVE_ALLOCATION_SIZE = 32;// 重点看这里,看注释// Convenience for JNI access@UnsupportedAppUsageprivate final long mNativePtr;

就是一个long类型而已啊,没有学过C/C++的朋友一定很惊讶,为什么一个Java中的long类型就能保存Native中的一个对象呢?这就是C/C++指针的神秘之处了,
这个long类型保存的不是一个普通的数字,而是对象的Native对象的一个内存地址。哦,原来Java并不直接保存C或者C++的对象,仅仅是保存它的一个地址而已,
当我们需要复用这个Native对象的时候只需要拿到这个long类型的地址,再通过指针的方式访问即可。就是这么简单。。。

So easy

牛刀初试一下

直接show me the code!!!

JNIActivity.java

public class JNIActivity extends AppCompatActivity {private Teacher teacher;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_j_n_i);teacher = new Teacher();teacher.initStudent();teacher.educationStudent(teacher.mNativePtr);}@Overrideprotected void onDestroy() {if(null != teacher){teacher.releaseStudent(teacher.mNativePtr);teacher = null;}super.onDestroy();}
}

新建一个java类:
Teacher.java

public class Teacher {public long mNativePtr = 0;/*** 初始化一个学生,并将指针地址保存在mNativePtr变量中*/public native void initStudent();/*** 根据学生的指针地址发起个性化教育* @param studentPtr*/public native void educationStudent(long studentPtr);/*** 释放学生对象,很关键的一步,否则就是可怕的内存泄漏* @param studentPtr*/public native void releaseStudent(long studentPtr);
}

新建C++对象类:

Student.h

#ifndef GROWING_STUDENT_H
#define GROWING_STUDENT_Hclass Student {public:char *name = nullptr;int age = 0;Student();~Student();};#endif //GROWING_STUDENT_H

Student.cpp

#include "Student.h"Student::Student() {}Student::~Student() {}

native-lib.cpp

extern "C"
JNIEXPORT void JNICALL
Java_com_flyer_bspatchupdate_jni_Teacher_initStudent(JNIEnv *env, jobject thiz) {Student *student = new Student;student->age = 18;student->name = "我是一名学生,我叫小明";// JNI 设置Java变量jclass jc = env->GetObjectClass(thiz);jfieldID jf = env->GetFieldID(jc, "mNativePtr", "J");env->SetLongField(thiz, jf, (jlong)student);
}extern "C"
JNIEXPORT void JNICALL
Java_com_flyer_bspatchupdate_jni_Teacher_educationStudent(JNIEnv *env, jobject thiz,jlong student_ptr) {if (0 != student_ptr) {Student *student = (Student*)student_ptr;student->age = student->age + 1;student->name;}
}extern "C"
JNIEXPORT void JNICALL
Java_com_flyer_bspatchupdate_jni_Teacher_releaseStudent(JNIEnv *env, jobject thiz,jlong student_ptr) {if (0 != student_ptr) {Student *student = (Student*)student_ptr;delete student;}
}

重要的注释已经写了,使用lldb调试发现在类TeachereducationStudent方法和releaseStudent方法中获取到的确是同一个对象。

能不能另辟蹊径

其实所谓的Java对象保存C或者C++对象就是为了建立Java对象与C或者C++对象的唯一对应关系,方便在下次JNI入口函数中能根据Java传递的对象获取到原来已生成的C或C++对象而已。
那么在我们学习过的数据结构中有没有这样的一种一一对应的映射的数据结构呢?如果有怎么利用起来呢?如果没有我能造一个轮子不?

我们程序员都说不要把时间浪费在造轮子之上,但是这是有前提的,不要重复造轮子这一说法在实际生产中很实用,但是却不适合放在我们学习的过程中。
我们在实际的项目中当然是建议使用业界成熟的普遍通用的轮子,这样能让我们把精力更多地放在我们的业务之上,做出更优秀的产品。

但是如果我们在学习的过程中如果不去模仿着造轮子,不去瞎搞折腾一下,你怎么知道原来知识还能这样子玩,怎么知道这个轮子能不能优化得更好呢?

关注我,一起进步,人生不止coding!!!

微信扫码关注

这篇关于NDK编程Java如何保存C或C++对象的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1096665

相关文章

Python中Tkinter GUI编程详细教程

《Python中TkinterGUI编程详细教程》Tkinter作为Python编程语言中构建GUI的一个重要组件,其教程对于任何希望将Python应用到实际编程中的开发者来说都是宝贵的资源,这篇文... 目录前言1. Tkinter 简介2. 第一个 Tkinter 程序3. 窗口和基础组件3.1 创建窗

利用c++判断水仙花数并输出示例代码

《利用c++判断水仙花数并输出示例代码》水仙花数是指一个三位数,其各位数字的立方和恰好等于该数本身,:本文主要介绍利用c++判断水仙花数并输出的相关资料,文中通过代码介绍的非常详细,需要的朋友可以... 以下是使用C++实现的相同逻辑代码:#include <IOStream>#include <vec

基于C++的UDP网络通信系统设计与实现详解

《基于C++的UDP网络通信系统设计与实现详解》在网络编程领域,UDP作为一种无连接的传输层协议,以其高效、低延迟的特性在实时性要求高的应用场景中占据重要地位,下面我们就来看看如何从零开始构建一个完整... 目录前言一、UDP服务器UdpServer.hpp1.1 基本框架设计1.2 初始化函数Init详解

Java中Map的五种遍历方式实现与对比

《Java中Map的五种遍历方式实现与对比》其实Map遍历藏着多种玩法,有的优雅简洁,有的性能拉满,今天咱们盘一盘这些进阶偏基础的遍历方式,告别重复又臃肿的代码,感兴趣的小伙伴可以了解下... 目录一、先搞懂:Map遍历的核心目标二、几种遍历方式的对比1. 传统EntrySet遍历(最通用)2. Lambd

Spring Boot 中 RestTemplate 的核心用法指南

《SpringBoot中RestTemplate的核心用法指南》本文详细介绍了RestTemplate的使用,包括基础用法、进阶配置技巧、实战案例以及最佳实践建议,通过一个腾讯地图路线规划的案... 目录一、环境准备二、基础用法全解析1. GET 请求的三种姿势2. POST 请求深度实践三、进阶配置技巧1

springboot+redis实现订单过期(超时取消)功能的方法详解

《springboot+redis实现订单过期(超时取消)功能的方法详解》在SpringBoot中使用Redis实现订单过期(超时取消)功能,有多种成熟方案,本文为大家整理了几个详细方法,文中的示例代... 目录一、Redis键过期回调方案(推荐)1. 配置Redis监听器2. 监听键过期事件3. Redi

Spring Boot 处理带文件表单的方式汇总

《SpringBoot处理带文件表单的方式汇总》本文详细介绍了六种处理文件上传的方式,包括@RequestParam、@RequestPart、@ModelAttribute、@ModelAttr... 目录方式 1:@RequestParam接收文件后端代码前端代码特点方式 2:@RequestPart接

SpringBoot整合Zuul全过程

《SpringBoot整合Zuul全过程》Zuul网关是微服务架构中的重要组件,具备统一入口、鉴权校验、动态路由等功能,它通过配置文件进行灵活的路由和过滤器设置,支持Hystrix进行容错处理,还提供... 目录Zuul网关的作用Zuul网关的应用1、网关访问方式2、网关依赖注入3、网关启动器4、网关全局变

SpringBoot全局异常拦截与自定义错误页面实现过程解读

《SpringBoot全局异常拦截与自定义错误页面实现过程解读》本文介绍了SpringBoot中全局异常拦截与自定义错误页面的实现方法,包括异常的分类、SpringBoot默认异常处理机制、全局异常拦... 目录一、引言二、Spring Boot异常处理基础2.1 异常的分类2.2 Spring Boot默

基于SpringBoot实现分布式锁的三种方法

《基于SpringBoot实现分布式锁的三种方法》这篇文章主要为大家详细介绍了基于SpringBoot实现分布式锁的三种方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、基于Redis原生命令实现分布式锁1. 基础版Redis分布式锁2. 可重入锁实现二、使用Redisso