android ndk jnienv,Android JNI和NDK学习(二):JNIEnv 和 JavaVM

概述

上篇学习了NDK相关知识,这篇继续学习JNI相关知识,这篇文章仅作为笔记,以防以后忘记

JNI的数据类型和类型描述符

在JNI开发中,java的数据类型并不能直接在JNI上直接使用,需要有一定的转化,比如java中的int在JNI中就是jint,下面我们来学习下数据类型

基本数据类型

Java数据类型

jni数据类型

描述

boolean

jboolean

无符号char类型

byte

jbyte

带符号8位整形

char

jchar

无符号的16位整形

short

jshort

带符号的16位整形

int

jint

带符号的32位整形

long

jlong

带符号的64位整形

float

jfloat

32位浮点型

引用数据类型

java类型

JNI类型

描述

java.lang.Object

jobject

可以表示任何java对象

java.lang.String

jstring

字符串对象

java.lang.Class

jclass

class对象

Object[]

jobjectArray

java任何对象数组的表现形式

boolean[]

jbooleanArray

布尔类型的数组

byte[]

jbyteArray

byte数组的表现形式

char[]

jcharArray

char数组的表现形式

short[]

jshortArray

short数组的表现形式

int[]

jintArray

int数组的表现形式

long[]

jlongArray

long数组的表现形式

float[]

jfloatArray

float数组的表现形式

double[]

jdoubleArray

double数组的表现形式

java.lang.Throwable

jthrowable

java throwable的表现形式

void

void

无类型

其实大部分就是在java的数据类型的前面加上了小写j来表示jni的数据类型

类型描述符

在JVM虚拟机中,存储数据类型名称的时候,是使用指定的描述符来使用,而不是我们使用的int,float来储存

java类型

类型描述符

int

I

long

J

byte

B

short

S

char

C

float

F

double

D

boolean

Z

void

V

其他引用数据类型

L+全类名+;

数组

[

方法

(参数)返回值

表示一个string类

类型

描述

java类型

java.lang.String

jni描述符

Ljava/lang/String;

就是L+全类名,其中.换成/,最后加上;

表示数组

类型

描述

java类型

String[]

jni描述符

[Ljava/;ang/String;

java类型

int[][]

jni描述符

[[I

表示方法

类型

描述

java类型

long f (int n,String s,int arr[]);

jni描述符

(ILjava/lang/String;[I)J

java类型

void f ();

jni类型

()V

JNIEnv 和 JavaVM

JavaVM

javaVM是java虚拟机在jni层的代表,一个进程只有一个JavaVM,所有的线程共用一个JavaVM

我们来看下JavaVM结构体

struct _JavaVM {

const struct JNIInvokeInterface* functions;

#if defined(__cplusplus)

jint DestroyJavaVM()

{ return functions->DestroyJavaVM(this); }

jint AttachCurrentThread(JNIEnv** p_env, void* thr_args)

{ return functions->AttachCurrentThread(this, p_env, thr_args); }

jint DetachCurrentThread()

{ return functions->DetachCurrentThread(this); }

jint GetEnv(void** env, jint version)

{ return functions->GetEnv(this, env, version); }

jint AttachCurrentThreadAsDaemon(JNIEnv** p_env, void* thr_args)

{ return functions->AttachCurrentThreadAsDaemon(this, p_env, thr_args); }

#endif /*__cplusplus*/

};

复制代码

这里值分析C++版的,可以看到所有的方法都是JNIInvokeInterface实现的,我们看下这个结构体

struct JNIInvokeInterface {

void* reserved0;

void* reserved1;

void* reserved2;

jint (*DestroyJavaVM)(JavaVM*);

jint (*AttachCurrentThread)(JavaVM*, JNIEnv**, void*);

jint (*DetachCurrentThread)(JavaVM*);

jint (*GetEnv)(JavaVM*, void**, jint);

jint (*AttachCurrentThreadAsDaemon)(JavaVM*, JNIEnv**, void*);

};

复制代码

我们看到JNIInvokeInterface结构体包含5个函数,看方法名大概能知道他们有什么作用,比如:GetEnv函数获取JNIEnv指针

当从Java层到Native层开发时,他会自动创建JavaVM对象,但是当Native层到Java层开发时,需要我们主动创建JavaVM对象,我们可以用下面的函数创建

jint JNI_CreateJavaVM(JavaVM **p_vm, void **p_env, void *vm_args);

第一个参数:指向JavaVM *的指针,函数调用成功会给JavaVM *赋值

第二个参数:指向JNIEnv *的指针,函数调用成功会给JNIEnv *赋值

第三个参数:是指向JavaVMInitArgs的指针,是初始化虚拟机的参数

复制代码

JNIEnv

JNIEnv是一个线程相关的结构体,该结构体代表了java在本线程的执行环境

JavaVM:JavaVM是java虚拟机在jni层的代表,全局只有一个

JNIEnv:每个线程都有一个,jni可能有多个JNIEnv

native环境创建线程,如果要访问jni,需要调用AttachCurrentThread方法进行关联,使用DetachCurrentThread接触关联

在_JavaVM结构体中,有一个方法getEnv()可以获取JNIEnv

jint GetEnv(JavaVM *vm, void **env, jint version);

第一个参数:JavaVM虚拟机对象

第二个参数:指向JNIEnv的指针

第三个参数:jni的版本,根据jdk的版本,目前有四种值,分别为 JNI_VERSION_1_1, JNI_VERSION_1_2, JNI_VERSION_1_4, JNI_VERSION_1_6

复制代码

函数调用成功会给JNIEnv赋值

JNIEnv的作用

我们先看下JNIEnv结构体

struct _JNIEnv {

/* do not rename this; it does not seem to be entirely opaque */

const struct JNINativeInterface* functions;

#if defined(__cplusplus)

jint GetVersion()

{ return functions->GetVersion(this); }

jclass DefineClass(const char *name, jobject loader, const jbyte* buf,

jsize bufLen)

{ return functions->DefineClass(this, name, loader, buf, bufLen); }

jclass FindClass(const char* name)

{ return functions->FindClass(this, name); }

jmethodID FromReflectedMethod(jobject method)

{ return functions->FromReflectedMethod(this, method); }

jfieldID FromReflectedField(jobject field)

{ return functions->FromReflectedField(this, field); }

...省略很多函数

}

复制代码

我们可以看到函数的实现最终还是交给了JNINativeInterface去实现,我们再看下这个结构体

struct JNINativeInterface {

void* reserved0;

void* reserved1;

void* reserved2;

void* reserved3;

jint (*GetVersion)(JNIEnv *);

jclass (*DefineClass)(JNIEnv*, const char*, jobject, const jbyte*,

jsize);

jclass (*FindClass)(JNIEnv*, const char*);

jmethodID (*FromReflectedMethod)(JNIEnv*, jobject);

jfieldID (*FromReflectedField)(JNIEnv*, jobject);

/* spec doesn't show jboolean parameter */

jobject (*ToReflectedMethod)(JNIEnv*, jclass, jmethodID, jboolean);

jclass (*GetSuperclass)(JNIEnv*, jclass);

jboolean (*IsAssignableFrom)(JNIEnv*, jclass, jclass);

/* spec doesn't show jboolean parameter */

jobject (*ToReflectedField)(JNIEnv*, jclass, jfieldID, jboolean);

jint (*Throw)(JNIEnv*, jthrowable);

jint (*ThrowNew)(JNIEnv *, jclass, const char *);

jthrowable (*ExceptionOccurred)(JNIEnv*);

void (*ExceptionDescribe)(JNIEnv*);

void (*ExceptionClear)(JNIEnv*);

void (*FatalError)(JNIEnv*, const char*);

...省略很多的方法

}

复制代码

这个结构体的作用是操作java层的入口,具体有俩个作用

调用java函数:使用JNIEnv调用java中的代码

操作java对象:java对象传入jni层是jstring,可以使用JNIEnv来操作这个对象

参考:

juejin.im/post/5d19bf…

www.jianshu.com/p/87ce6f565…

blog.csdn.net/afei__/arti…

b739ec46bb5c46d9c0aa4ce35ba1ea56.png

关于找一找教程网

本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。

本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。

[Android JNI和NDK学习(二):JNIEnv 和 JavaVM]http://www.zyiz.net/tech/detail-138280.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值