JNI学习笔记:JNIEnv、jobject与jclass详解

本文介绍JNI编程中的JNIEnv、jobject和jclass三种基本类型。JNIEnv是JNI接口指针,指向本地方法使用的函数表;jobject与jclass用于访问Java对象和类。了解这些类型有助于深入理解JNI的工作原理。
该文章已生成可运行项目,


1 前言

在进行JNI编程开发的时候,使用javah生成Native方法对应的Native函数声明,会发现所有的Native函数的第一个参数永远是JNIEnv指针,而第二个参数永远是jobject或jclass中的一个。JNIEnv指针指代何物?具有何种功能?jobject和jclass又有何区别?
本文简单介绍了JNI编程中JNIEnvjobjectjclass这三种基本类型。

2 JNIEnv指针

JNIEnv,顾名思义,指代了Java本地接口环境(Java Native Interface Environment),是一个JNI接口指针,指向了本地方法的一个函数表,该函数表中的每一个成员指向了一个JNI函数,本地方法通过JNI函数来访问JVM中的数据结构,详情如下图:
这里写图片描述

JNIEnv指针在<jni.h>文件中的具体实现是一个包含诸多JNI函数的结构体,在C语言中该结构体的名字定义为JNIEnv_。局部摘要如下:

/*
 * We use inlined functions for C++ so that programmers can write:
 *
 *    env->FindClass("java/lang/String")
 *
 * in C++ rather than:
 *
 *    (*env)->FindClass(env, "java/lang/String")
 *
 * in C.
 */

struct JNIEnv_ {
    const struct JNINativeInterface_ *functions;
#ifdef __cplusplus

    jint GetVersion() {
        return functions->GetVersion(this);
    }
    jclass DefineClass(const char *name, jobject loader, const jbyte *buf,
                       jsize len) {
        return functions->DefineClass(this, name, loader, buf, len);
    }
    ...
     jclass GetObjectClass(jobject obj) {
        return functions->GetObjectClass(this,obj);
    }
    jboolean IsInstanceOf(jobject obj, jclass clazz) {
        return functions->IsInstanceOf(this,obj,clazz);
    }

    jmethodID GetMethodID(jclass clazz, const char *name,
                          const char *sig) {
        return functions->GetMethodID(this,clazz,name,sig);
    }
    ...
 }

深入去看JNIEnv结构体的话,不难发现,这个结构体当中包含了几乎有所的JNI函数,大致可以分为如下几类:

函数名备注
NewObject创建Java类中的对象
NewString创建Java类中的String对象
New<Type>Array创建类型为Type的数组对象
Get<Type>Field获取类型为Type的字段
Set<Type>Field设置类型为Type的字段的值
GetStatic<Type>Field获取类型为Type的static的字段
SetStatic<Type>Field设置类型为Type的static的字段的值
Call<Type>Method调用返回类型为Type的方法
CallStatic<Type>Method调用返回值类型为Type的static方法

3 jobject与jclass类型

jobjectjclass通常作为JNI函数的第二个参数,当所声明Native方法是静态方法时,对应参数jclass,因为静态方法不依赖对象实例,而依赖于类,所以参数中传递的是一个jclass类型。相反,如果声明的Native方法时非静态方法时,那么对应参数是jobject
其在`<jni.h>``中的定义如下:

typedef _jobject *jobject;
typedef _jclass *jclass;
...
class _jobject {};
class _jclass : public _jobject {};
...

为了能够在Native层访问Java中的类和对象,jobjectjclass 分别指代了其所指代的类和对象,进而访问成员方法和成员变量等。但其实,我们一般使用javah指令直接生成Native函数的函数原型,故而不必纠结该使用哪种类型。

本文章已经生成可运行项目
void TestSuite_update2dsdk_cpp_802ca10e::test_Java_com_isa_navi_jni_hmi_HmiProxyJNI_InitializeCpp_1() { /* Pre-condition initialization */ /* Initializing argument 1 (env) */ ::JNIEnv * _env = 0 ; /* Initializing argument 2 (thiz) */ ::jobject _thiz = 0 ; /* Pre-condition report */ CPPTEST_REPORT_PTR("Input: JNIEnv * _env ", ( _env )); CPPTEST_REPORT_PTR("Input: ::jobject _thiz", ( _thiz )); /* Tested function call */ ::Java_com_isa_navi_jni_hmi_HmiProxyJNI_InitializeCpp(_env, _thiz); /* Post-condition report */ CPPTEST_REPORT_PTR("Output: JNIEnv * _env ", ( _env )); CPPTEST_REPORT_PTR("Output: ::jobject _thiz", ( _thiz )); /* Post-condition check */ CPPTEST_ASSERT_EQUAL(NULL, ( _env )); CPPTEST_ASSERT_EQUAL(NULL, ( _thiz )); } /* CPPTEST_TEST_CASE_END test_Java_com_isa_navi_jni_hmi_HmiProxyJNI_InitializeCpp_1 */ /* CPPTEST_TEST_CASE_BEGIN test_Java_com_isa_navi_jni_hmi_HmiProxyJNI_InitializeCpp_2 */ /* CPPTEST_TEST_CASE_CONTEXT void Java_com_isa_navi_jni_hmi_HmiProxyJNI_InitializeCpp(JNIEnv *, jobject) */ void TestSuite_update2dsdk_cpp_802ca10e::test_Java_com_isa_navi_jni_hmi_HmiProxyJNI_InitializeCpp_2() { /* Pre-condition initialization */ /* Initializing argument 1 (env) */ ::JNIEnv _env_0 ; ::JNIEnv * _env = & _env_0; /* Initializing argument 2 (thiz) */ ::jobject _thiz = 0 ; /* Pre-condition report */ CPPTEST_REPORT_PTR("Input: JNIEnv * _env ", ( _env )); CPPTEST_REPORT_PTR("Input: ::jobject _thiz", ( _thiz )); /* Tested function call */ ::Java_com_isa_navi_jni_hmi_HmiProxyJNI_InitializeCpp(_env, _thiz); /* Post-condition report */ CPPTEST_REPORT_PTR("Output: JNIEnv * _env ", ( _env )); CPPTEST_REPORT_PTR("Output: ::jobject _thiz", ( _thiz )); /* Post-condition check */ CPPTEST_ASSERT(0 != ( _env )); CPPTEST_ASSERT_EQUAL(NULL, ( _thiz )); } /* CPPTEST_TEST_CASE_END test_Java_com_isa_navi_jni_hmi_HmiProxyJNI_InitializeCpp_2 */ /* CPPTEST_TEST_CASE_BEGIN test_Java_com_isa_navi_jni_hmi_HmiProxyJNI_InitializeCpp_3 */ /* CPPTEST_TEST_CASE_CONTEXT void Java_com_isa_navi_jni_hmi_HmiProxyJNI_InitializeCpp(JNIEnv *, jobject) */ void TestSuite_update2dsdk_cpp_802ca10e::test_Java_com_isa_navi_jni_hmi_HmiProxyJNI_InitializeCpp_3() { /* Pre-condition initialization */ /* Initializing argument 1 (env) */ ::JNIEnv * _env = 0 ; /* Initializing argument 2 (thiz) */ ::_jobject _thiz_0 ; ::jobject _thiz = & _thiz_0; /* Pre-condition report */ CPPTEST_REPORT_PTR("Input: JNIEnv * _env ", ( _env )); CPPTEST_REPORT_PTR("Input: ::jobject _thiz", ( _thiz )); /* Tested function call */ ::Java_com_isa_navi_jni_hmi_HmiProxyJNI_InitializeCpp(_env, _thiz); /* Post-condition report */ CPPTEST_REPORT_PTR("Output: JNIEnv * _env ", ( _env )); CPPTEST_REPORT_PTR("Output: ::jobject _thiz", ( _thiz )); /* Post-condition check */ CPPTEST_ASSERT_EQUAL(NULL, ( _env )); CPPTEST_ASSERT(0 != ( _thiz )); } /* CPPTEST_TEST_CASE_END test_Java_com_isa_navi_jni_hmi_HmiProxyJNI_InitializeCpp_3 */ /* CPPTEST_TEST_CASE_BEGIN test_Java_com_isa_navi_jni_hmi_HmiProxyJNI_InitializeCpp_4 */ /* CPPTEST_TEST_CASE_CONTEXT void Java_com_isa_navi_jni_hmi_HmiProxyJNI_InitializeCpp(JNIEnv *, jobject) */ void TestSuite_update2dsdk_cpp_802ca10e::test_Java_com_isa_navi_jni_hmi_HmiProxyJNI_InitializeCpp_4() { /* Pre-condition initialization */ /* Initializing argument 1 (env) */ ::JNIEnv _env_0 ; ::JNIEnv * _env = & _env_0; /* Initializing argument 2 (thiz) */ ::_jobject _thiz_1 ; ::jobject _thiz = & _thiz_1; /* Pre-condition report */ CPPTEST_REPORT_PTR("Input: JNIEnv * _env ", ( _env )); CPPTEST_REPORT_PTR("Input: ::jobject _thiz", ( _thiz )); /* Tested function call */ ::Java_com_isa_navi_jni_hmi_HmiProxyJNI_InitializeCpp(_env, _thiz); /* Post-condition report */ CPPTEST_REPORT_PTR("Output: JNIEnv * _env ", ( _env )); CPPTEST_REPORT_PTR("Output: ::jobject _thiz", ( _thiz )); /* Post-condition check */ CPPTEST_ASSERT(0 != ( _env )); CPPTEST_ASSERT(0 != ( _thiz )); } void TestSuite_update2dsdk_cpp_802ca10e::test_Java_com_isa_navi_jni_hmi_HmiProxyJNI_InitializeCpp() { /* Pre-condition initialization */ /* Initializing argument 1 (env) */ ::JNIEnv * _env = 0 ; /* Initializing argument 2 (thiz) */ ::jobject _thiz = 0 ; /* Tested function call */ ::Java_com_isa_navi_jni_hmi_HmiProxyJNI_InitializeCpp(_env, _thiz); /* Post-condition check */ CPPTEST_ASSERT_EQUAL(NULL, ( _env )); CPPTEST_ASSERT_EQUAL(NULL, ( _thiz )); } 上述是目前的五个测试用例 测试目标:extern "C" JNIEXPORT void JNICALL Java_com_isa_navi_jni_hmi_HmiProxyJNI_InitializeCpp(JNIEnv *env, jobject thiz) { lantu::isa::WriteAndroidLog(2, "Java_com_isa_navi_jni_hmi_HmiProxyJNI_InitializeCpp"); if(Update::getinstance()->javaVm == nullptr) { JavaVM* javaVm; jint ret = env->GetJavaVM(&javaVm); if (ret != JNI_OK) return; jclass cls = env->FindClass("com/isa/navi/jni/hmi/HmiJNIImpl"); if (cls == NULL) return; jmethodID jmid = env->GetStaticMethodID(cls, "getInstance", "()Lcom/isa/navi/jni/hmi/HmiJNIImpl;"); if (jmid == NULL) return; jobject carobj = env->CallStaticObjectMethod(cls, jmid); if (carobj == NULL) return; jobject carObj = env->NewGlobalRef(carobj); Update::getinstance()->javaVm = javaVm; Update::getinstance()->carObj = carObj; } WriteAndroidLog(1,"ISA_NAVI_UPDATE HmiProxyJNI_InitializeCpp"); } 我的目的是通过..._5 ..._6 等更多的测试用例提高分支覆盖率
07-23
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值