NDK 开发中 Native 与 Java 交互

简介: Java 与 JNI 数据类型对应关系

作者:字节流动

来源:https://blog.csdn.net/Kennethdroid/article/details/86418725


Java 与 JNI 数据类型对应关系

Java 数据类型 JNI 数据类型
boolean jboolean
byte jbyte
char jchar
short jshort
int jint
long jlong
float jfloat
double jdouble
String jstring
Object jobject
byte[] jbyteArray
Object[] jobjectArray

Native 中的签名

NDK 开发中会用到 Java 对象的属性签名和方法签名,用于区分不同的属性和方法。

属性签名

属性的签名就是属性类型的简称。

属性类型与其签名的对应关系如下:

属性类型 类型签名
boolean Z
byte B
char C
short S
int I
long L
float F
double D
void V
String Ljava/lang/String;
Object 以 L 开头,后加完整的包名,并以分号结束
byte[] [B
Object[] 以 [ 开头,后加对象类型签名,例如 String[] 对应 [Ljava/lang/String;

方法签名

方法签名格式:

(参数类型签名)返回值类型签名

那么如何获取方法签名?

执行命令 javah

javah com.haohao.hellojni.NativeTest.class 生成 com_haohao_hellojni_NativeTest.h 文件,文件中便标出了方法的 Signature 。

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_haohao_hellojni_NativeTest */
#ifndef _Included_com_haohao_hellojni_NativeTest
#define _Included_com_haohao_hellojni_NativeTest
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_haohao_hellojni_NativeTest
 * Method:    getString
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_haohao_hellojni_NativeTest_getString__
  (JNIEnv *, jobject);
/*
 * Class:     com_haohao_hellojni_NativeTest
 * Method:    getString
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_haohao_hellojni_NativeTest_getString__Ljava_lang_String_2
  (JNIEnv *, jobject, jstring);
/*
 * Class:     com_haohao_hellojni_NativeTest
 * Method:    getInt
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_com_haohao_hellojni_NativeTest_getInt__
  (JNIEnv *, jobject);
/*
 * Class:     com_haohao_hellojni_NativeTest
 * Method:    getInt
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_com_haohao_hellojni_NativeTest_getInt__I
  (JNIEnv *, jobject, jint);
/*
 * Class:     com_haohao_hellojni_NativeTest
 * Method:    input
 * Signature: (Ljava/lang/String;I)V
 */
JNIEXPORT void JNICALL Java_com_haohao_hellojni_NativeTest_input__Ljava_lang_String_2I
  (JNIEnv *, jobject, jstring, jint);
/*
 * Class:     com_haohao_hellojni_NativeTest
 * Method:    input
 * Signature: ([Ljava/lang/String;I)V
 */
JNIEXPORT void JNICALL Java_com_haohao_hellojni_NativeTest_input___3Ljava_lang_String_2I
  (JNIEnv *, jobject, jobjectArray, jint);
/*
 * Class:     com_haohao_hellojni_NativeTest
 * Method:    getBytes
 * Signature: ([Ljava/lang/String;Ljava/lang/String;)[B
 */
JNIEXPORT jbyteArray JNICALL Java_com_haohao_hellojni_NativeTest_getBytes
  (JNIEnv *, jobject, jobjectArray, jstring);
#ifdef __cplusplus
}
#endif
#endif

Native 与 Java 交互

设置一个简单的类 NativeUtils.java 用于测试,Native 与 Java 交互的实现类似于 Java 的反射机制。

package com.haohao.hellojni;
import android.util.Log;
/**
 * author: haohao
 * time: 2018/1/1
 * mail: haohaochang86@gmail.com
 * desc: description
 */
public class NativeUtils {
    static {
        System.loadLibrary("native-utils");
    }
    private static final String TAG = "NativeUtils";
    public static int staticProp = -1;
    public int prop = -1;
    public String getStringFromJava(String str){
        Log.i(TAG, "getStringFromJava: "+ str);
        return "Hello C , I am from Java.";
    }
    public static String getStringFromJavaStatic(String str){
        Log.i(TAG, "getStringFromJavaStatic: " + str);
        return "Hello C , I am from Java static.";
    }
    public native void accessJavaClassProp();
    public native void callJavaClassMethod();
    public static native void accessStaticJavaProp();
    public static native void callStaticJavaMethod();
}

访问 Java 对象的非静态属性

JNIEXPORT void JNICALL
Java_com_haohao_hellojni_NativeUtils_accessJavaClassProp(JNIEnv *env, jobject instance) {
    //访问 Java 对象的非静态属性
    //通过 JNIEnv 和对象 instance 实例拿到 class 。
    jclass cls = (*env)->GetObjectClass(env, instance);
    //获取属性的 field id
    jfieldID fid = (*env)->GetFieldID(env, cls, "prop", "I");
    //通过 field id 获取属性的值
    jint prop = (*env)->GetIntField(env, instance, fid);
    //在 Native 层修改属性
    prop += 101;
    (*env)->SetIntField(env, instance, fid, prop);
}

调用 Java 对象的非静态方法

JNIEXPORT void JNICALL
Java_com_haohao_hellojni_NativeUtils_callJavaClassMethod(JNIEnv *env, jobject instance) {
    //调用 Java 对象的非静态方法
    jclass myClass = (*env)->GetObjectClass(env, instance);
    //获取发方法的 method id
    jmethodID mid = (*env)->GetMethodID(env, myClass, "getStringFromJava", "(Ljava/lang/String;)Ljava/lang/String;");
    //调用 Java 对象的方法
    jstring  jstr = (*env)->CallObjectMethod(env, instance, mid, (*env)->NewStringUTF(env, "Hello Java, I am From C."));
    //jstring 转换为 c 的字符串
    const char* cstr = (*env)->GetStringUTFChars(env, jstr, NULL);
    LOGD("%s", cstr);
    //注意区别对待 Java 字符串和 C 的字符串,除了基本数据类型之外,其他都需要进行类型转换
    //释放资源
    (*env)->ReleaseStringUTFChars(env, jstr, cstr);
}

访问 Java 对象的静态属性

JNIEXPORT void JNICALL
Java_com_haohao_hellojni_NativeUtils_accessStaticJavaProp(JNIEnv *env, jclass type) {
    //访问 Java 对象的静态属性,
    jfieldID fid = (*env)->GetStaticFieldID(env, type, "staticProp", "I");
    jint staticProp = (*env)->GetStaticIntField(env, type, fid);
    staticProp += 101;
    (*env)->SetStaticIntField(env, type, fid, staticProp);
}

调用 Java 对象的静态方法

JNIEXPORT void JNICALL
Java_com_haohao_hellojni_NativeUtils_callStaticJavaMethod(JNIEnv *env, jclass type) {
    //调用 Java 对象的静态方法
    jmethodID mid = (*env)->GetStaticMethodID(env, type, "getStringFromJavaStatic", "(Ljava/lang/String;)Ljava/lang/String;");
    jstring jstr = (*env)->CallStaticObjectMethod(env, type, mid, (*env)->NewStringUTF(env, "Hello Java, I am From C."));
    const char* cstr = (*env)->GetStringUTFChars(env, jstr, NULL);
    LOGD("%s", cstr);
    //释放资源
    (*env)->ReleaseStringUTFChars(env, jstr, cstr);
}

测试

nativeUtils = new NativeUtils();
Log.i(TAG, "old prop : " + nativeUtils.prop);
nativeUtils.accessJavaClassProp();
Log.i(TAG, "new prop : " + nativeUtils.prop);
Log.i(TAG, "old static prop : " + NativeUtils.staticProp);
NativeUtils.accessStaticJavaProp();
Log.i(TAG, "new static prop : " + NativeUtils.staticProp);
nativeUtils.callJavaClassMethod();
NativeUtils.callStaticJavaMethod();

native-utils.c 完整代码

//
// Created by haohao on 2018/1/1.
//
#include <jni.h>
#include <android/log.h>
#define TAG "native-utils"
#define LOGD(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定义LOGD类型
JNIEXPORT void JNICALL
Java_com_haohao_hellojni_NativeUtils_accessJavaClassProp(JNIEnv *env, jobject instance) {
    //访问 Java 对象的非静态属性
    //通过 JNIEnv 和对象 instance 实例拿到 class 。
    jclass cls = (*env)->GetObjectClass(env, instance);
    //获取属性的 field id
    jfieldID fid = (*env)->GetFieldID(env, cls, "prop", "I");
    //通过 field id 获取属性的值
    jint prop = (*env)->GetIntField(env, instance, fid);
    //在 Native 层修改属性
    prop += 101;
    (*env)->SetIntField(env, instance, fid, prop);
}
JNIEXPORT void JNICALL
Java_com_haohao_hellojni_NativeUtils_callJavaClassMethod(JNIEnv *env, jobject instance) {
    //调用 Java 对象的非静态方法
    jclass myClass = (*env)->GetObjectClass(env, instance);
    //获取发方法的 method id
    jmethodID mid = (*env)->GetMethodID(env, myClass, "getStringFromJava", "(Ljava/lang/String;)Ljava/lang/String;");
    //调用 Java 对象的方法
    jstring  jstr = (*env)->CallObjectMethod(env, instance, mid, (*env)->NewStringUTF(env, "Hello Java, I am From C."));
    //jstring 转换为 c 的字符串
    const char* cstr = (*env)->GetStringUTFChars(env, jstr, NULL);
    LOGD("%s", cstr);
    //注意区别对待 Java 字符串和 C 的字符串,除了基本数据类型之外,其他都需要进行类型转换
    //释放资源
    (*env)->ReleaseStringUTFChars(env, jstr, cstr);
}
JNIEXPORT void JNICALL
Java_com_haohao_hellojni_NativeUtils_accessStaticJavaProp(JNIEnv *env, jclass type) {
    //访问 Java 对象的静态属性,
    jfieldID fid = (*env)->GetStaticFieldID(env, type, "staticProp", "I");
    jint staticProp = (*env)->GetStaticIntField(env, type, fid);
    staticProp += 101;
    (*env)->SetStaticIntField(env, type, fid, staticProp);
}
JNIEXPORT void JNICALL
Java_com_haohao_hellojni_NativeUtils_callStaticJavaMethod(JNIEnv *env, jclass type) {
    //调用 Java 对象的静态方法
    jmethodID mid = (*env)->GetStaticMethodID(env, type, "getStringFromJavaStatic", "(Ljava/lang/String;)Ljava/lang/String;");
    jstring jstr = (*env)->CallStaticObjectMethod(env, type, mid, (*env)->NewStringUTF(env, "Hello Java, I am From C."));
    const char* cstr = (*env)->GetStringUTFChars(env, jstr, NULL);
    LOGD("%s", cstr);
    //释放资源
    (*env)->ReleaseStringUTFChars(env, jstr, cstr);
}

结果

I/MainActivity: old prop : -1
I/MainActivity: new prop : 100
I/MainActivity: old static prop : -1
I/MainActivity: new static prop : 100
I/NativeUtils: getStringFromJava: Hello Java, I am From C.
I/native-utils: Hello C , I am from Java.
I/NativeUtils: getStringFromJavaStatic: Hello Java, I am From C.
I/native-utils: Hello C , I am from Java static.


NDK 开发系列文章:


「视频云技术」你最值得关注的音视频技术公众号,每周推送来自阿里云一线的实践技术文章,在这里与音视频领域一流工程师交流切磋。

阿里云社区.png

相关文章
|
2月前
|
安全 前端开发 Java
《深入理解Spring》:现代Java开发的核心框架
Spring自2003年诞生以来,已成为Java企业级开发的基石,凭借IoC、AOP、声明式编程等核心特性,极大简化了开发复杂度。本系列将深入解析Spring框架核心原理及Spring Boot、Cloud、Security等生态组件,助力开发者构建高效、可扩展的应用体系。(238字)
|
3月前
|
消息中间件 人工智能 Java
抖音微信爆款小游戏大全:免费休闲/竞技/益智/PHP+Java全筏开源开发
本文基于2025年最新行业数据,深入解析抖音/微信爆款小游戏的开发逻辑,重点讲解PHP+Java双引擎架构实战,涵盖技术选型、架构设计、性能优化与开源生态,提供完整开源工具链,助力开发者从理论到落地打造高留存、高并发的小游戏产品。
|
3月前
|
存储 Java 关系型数据库
Java 项目实战基于面向对象思想的汽车租赁系统开发实例 汽车租赁系统 Java 面向对象项目实战
本文介绍基于Java面向对象编程的汽车租赁系统技术方案与应用实例,涵盖系统功能需求分析、类设计、数据库设计及具体代码实现,帮助开发者掌握Java在实际项目中的应用。
147 0
|
4月前
|
安全 Java 数据库
Java 项目实战病人挂号系统网站设计开发步骤及核心功能实现指南
本文介绍了基于Java的病人挂号系统网站的技术方案与应用实例,涵盖SSM与Spring Boot框架选型、数据库设计、功能模块划分及安全机制实现。系统支持患者在线注册、登录、挂号与预约,管理员可进行医院信息与排班管理。通过实际案例展示系统开发流程与核心代码实现,为Java Web医疗项目开发提供参考。
244 2
|
4月前
|
JavaScript 安全 前端开发
Java开发:最新技术驱动的病人挂号系统实操指南与全流程操作技巧汇总
本文介绍基于Spring Boot 3.x、Vue 3等最新技术构建现代化病人挂号系统,涵盖技术选型、核心功能实现与部署方案,助力开发者快速搭建高效、安全的医疗挂号平台。
256 3
|
4月前
|
移动开发 Cloud Native 安全
Java:跨平台之魂,企业级开发的磐石
Java:跨平台之魂,企业级开发的磐石
|
算法 Java C++
【Java】深入理解Java中的Native关键字
【Java】深入理解Java中的Native关键字
584 0
|
2月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
191 1