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

相关文章

SpringBoot 获取请求参数的常用注解及用法

《SpringBoot获取请求参数的常用注解及用法》SpringBoot通过@RequestParam、@PathVariable等注解支持从HTTP请求中获取参数,涵盖查询、路径、请求体、头、C... 目录SpringBoot 提供了多种注解来方便地从 HTTP 请求中获取参数以下是主要的注解及其用法:1

HTTP 与 SpringBoot 参数提交与接收协议方式

《HTTP与SpringBoot参数提交与接收协议方式》HTTP参数提交方式包括URL查询、表单、JSON/XML、路径变量、头部、Cookie、GraphQL、WebSocket和SSE,依据... 目录HTTP 协议支持多种参数提交方式,主要取决于请求方法(Method)和内容类型(Content-Ty

深度解析Java @Serial 注解及常见错误案例

《深度解析Java@Serial注解及常见错误案例》Java14引入@Serial注解,用于编译时校验序列化成员,替代传统方式解决运行时错误,适用于Serializable类的方法/字段,需注意签... 目录Java @Serial 注解深度解析1. 注解本质2. 核心作用(1) 主要用途(2) 适用位置3

深入浅出Spring中的@Autowired自动注入的工作原理及实践应用

《深入浅出Spring中的@Autowired自动注入的工作原理及实践应用》在Spring框架的学习旅程中,@Autowired无疑是一个高频出现却又让初学者头疼的注解,它看似简单,却蕴含着Sprin... 目录深入浅出Spring中的@Autowired:自动注入的奥秘什么是依赖注入?@Autowired

Spring 依赖注入与循环依赖总结

《Spring依赖注入与循环依赖总结》这篇文章给大家介绍Spring依赖注入与循环依赖总结篇,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. Spring 三级缓存解决循环依赖1. 创建UserService原始对象2. 将原始对象包装成工

Java中如何正确的停掉线程

《Java中如何正确的停掉线程》Java通过interrupt()通知线程停止而非强制,确保线程自主处理中断,避免数据损坏,线程池的shutdown()等待任务完成,shutdownNow()强制中断... 目录为什么不强制停止为什么 Java 不提供强制停止线程的能力呢?如何用interrupt停止线程s

SpringBoot请求参数传递与接收示例详解

《SpringBoot请求参数传递与接收示例详解》本文给大家介绍SpringBoot请求参数传递与接收示例详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋... 目录I. 基础参数传递i.查询参数(Query Parameters)ii.路径参数(Path Va

SpringBoot路径映射配置的实现步骤

《SpringBoot路径映射配置的实现步骤》本文介绍了如何在SpringBoot项目中配置路径映射,使得除static目录外的资源可被访问,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一... 目录SpringBoot路径映射补:springboot 配置虚拟路径映射 @RequestMapp

Java MCP 的鉴权深度解析

《JavaMCP的鉴权深度解析》文章介绍JavaMCP鉴权的实现方式,指出客户端可通过queryString、header或env传递鉴权信息,服务器端支持工具单独鉴权、过滤器集中鉴权及启动时鉴权... 目录一、MCP Client 侧(负责传递,比较简单)(1)常见的 mcpServers json 配置

GSON框架下将百度天气JSON数据转JavaBean

《GSON框架下将百度天气JSON数据转JavaBean》这篇文章主要为大家详细介绍了如何在GSON框架下实现将百度天气JSON数据转JavaBean,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录前言一、百度天气jsON1、请求参数2、返回参数3、属性映射二、GSON属性映射实战1、类对象映