android jni 中jnienv,android JNI中JNIEnv類型和jobject類型的解釋
JNIEXPORT void JNICALL Java_com_jni_demo_JNIDemo_sayHello (JNIEnv *env, jobject obj)
{
cout<
}
對於這個方法參數中的JNIEnv* env參數的解釋:
JNIEnv類型實際上代表了Java環境,通過這個JNIEnv* 指針,就可以對Java端的代碼進行操作。例如,創建Java類中的對象,調用Java對象的方法,獲取Java對象中的屬性等等。JNIEnv的指針會被JNI傳入到本地方法的實現函數中來對Java端的代碼進行操作。
JNIEnv類中有很多函數可以用:
NewObject:創建Java類中的對象
NewString:創建Java類中的String對象
NewArray:創建類型為Type的數組對象
GetField:獲取類型為Type的字段
SetField:設置類型為Type的字段的值
GetStaticField:獲取類型為Type的static的字段
SetStaticField:設置類型為Type的static的字段的值
CallMethod:調用返回類型為Type的方法
CallStaticMethod:調用返回值類型為Type的static方法
等許多的函數,具體的可以查看jni.h文件中的函數名稱。
參數:jobject obj的解釋:
如果native方法不是static的話,這個obj就代表這個native方法的類實例
如果native方法是static的話,這個obj就代表這個native方法的類的class對象實例(static方法不需要類實例的,所以就代表這個類的class對象)
下面來看一下Java和C++中的基本類型的映射關系:
為了能夠在C/C++中使用Java類,jni.h頭文件中專門定義了jclass類型來表示Java中的Class類
JNIEnv類中有如下幾個簡單的函數可以取得jclass:
jclass FindClass(const char* clsName):通過類的名稱(類的全名,這時候包名不是用.號,而是用/來區分的)來獲取jclass
如: jclass str= env->FindClass("java/lang/String");獲取Java中的String對象的class對象。
jclass GetObjectClass(jobject obj):通過對象實例來獲取jclass,相當於java中的getClass方法
jclass GetSuperClass(jclass obj):通過jclass可以獲取其父類的jclass對象
在C/C++本地代碼中訪問Java端的代碼,一個常見的應用就是獲取類的屬性和調用類的方法,為了在C/C++中表示屬性和方法,JNI在jni.h頭文件中定義了jfieldId,jmethodID類型來分別代表Java端的屬性和方法
我們在訪問,或者設置Java屬性的時候,首先就要先在本地代碼取得代表該Java屬性的jfieldID,然后才能在本地代碼中進行Java屬性操作,同樣的,我們需要呼叫Java端的方法時,也是需要取得代表該方法的jmethodID才能進行Java方法調用
使用JNIEnv的:
GetFieldID/GetMethodID
GetStaticFieldID/GetStaticMethodID
來取得相應的jfieldID和jmethodID
下面來具體看一下這幾個方法:
GetFieldID(jclass clazz,const char* name,const char* sign)
方法的參數說明:
clazz:這個簡單就是這個方法依賴的類對象的class對象
name:這個是這個字段的名稱
sign:這個是這個字段的簽名(我們知道每個變量,每個方法都是有簽名的)
GetMethodID也能夠取得構造函數的jmethodID,創建一個Java對象時可以調用指定的構造方法,這個將在后面向大家介紹:
如:env->GetMethodID(data_Class,"","()V");
下面看一下簽名的格式:
通過例子來看一下這些方法的使用
packagecom.jni.demo;public classJNIDemo {public int number = 0;//定義一個屬性//定義一個本地方法
public native voidsayHello();public static voidmain(String[] args){//調用動態鏈接庫
System.loadLibrary("JNIDemo");
JNIDemo jniDemo= newJNIDemo();
jniDemo.sayHello();
System.out.print(jniDemo.number);
}
}
在來看一下C++代碼:
#include#include"com_jni_demo_JNIDemo.h"JNIEXPORTvoid JNICALL Java_com_jni_demo_JNIDemo_sayHello (JNIEnv *env, jobject obj)
{//獲取obj中對象的class對象
jclass clazz = env->GetObjectClass(obj);//獲取Java中的number字段的id(最后一個參數是number的簽名)
jfieldID id_number = env->GetFieldID(clazz,"number","I");//獲取number的值
jint number = env->GetIntField(obj,id_number);//輸出到控制台
cout<
env->SetIntField(obj,id_number,100L);
}
編譯成功后,在Eclipse運行后的結果:
第一個0是在C++代碼中的cout<
第二個100是在Java中的System.out.println(jniDemo.number);
JNIEnv提供了眾多的CallMethod和CallStaticMethod,還有CallNonvirtualMethod函數,需要通過GetMethodID取得相應方法的jmethodID來傳入到上述函數的參數中
調用示例方法的三種形式:
CallMethod(jobject obj,jmethodID id,....);
CallMethod(jobject obj,jmethodID id,va_list lst);
CallMethod(jobject obj,jmethodID id,jvalue* v);
第一種是最常用的方式
第二種是當調用這個函數的時候有一個指向參數表的va_list變量時使用的(很少使用)
第三種是當調用這個函數的時候有一個指向jvalue或jvalue數組的指針時用的
說明:
jvalue在jni.h頭文件中定義是一個union聯合體,在C/C++中,我們知道union是可以存放不同類型的值,但是當你給其中一個類型賦值之后,這個union就是這種類型了,比如你給jvalue中的s賦值的話,jvalue就變成了jshort類型了,所以我們可以定義一個jvalue數組(這樣就可以包含多種類型的參數了)傳遞到方法中。
假如現在Java中有這樣的一個方法:
boolean function(int a,double b,char c)
{
........
}
(1) 在C++中使用第一種方式調用function方法:
env->CallBooleanMethod(obj , id_function , 10L, 3.4 , L'a')
obj是方法funtion的對象
id_function是方法function的id;可以通過GetMethodID()方法獲取
然后就是對應的參數,這個和Java中的可變參數類似,對於最后一個char類型的參數L'a',為什么前面要加一個L,原因是Java中的字符時Unicode雙字節的,而C++中的字符時單字節的,所以要變成寬字符,前面加一個L
(2) 在C++中使用第三種法師調用function方法:
jvalue* args = new jvalue[3];//定義jvalue數組
args[0].i = 10L;//i是jvalue中的jint值
args[1].d = 3.44;
args[2].c = L'a';
env->CallBooleanMethod(obj, id_function, args);
delete[] args;//是否指針堆內存
例子:C++中調用Java中的方法:
Java代碼:
public double max(double value1,double value2){
return value1>value2 ? value1:value2;
}
JNIEXPORT void JNICALL Java_com_jni_demo_JNIDemo_sayHello (JNIEnv *env, jobject obj)
{//獲取obj中對象的class對象
jclass clazz = env->GetObjectClass(obj);//獲取Java中的max方法的id(最后一個參數是max方法的簽名)
jmethodID id_max = env->GetMethodID(clazz,"max","(DD)D");//調用max方法
jdouble doubles = env->CallDoubleMethod(obj,id_max,1.2,3.4);//輸出返回值
cout<
}
C++和Java對於繼承后執行的是父類的還是子類的方法是有區別的,在Java中所有的方法都是virtual的,所以總是調用子類的方法,所以CallNonVirtualMethod這個方法就出來了,這個方法就可以幫助我們調用Java中的父類的方法:
在JNI中定義的CallNonvirtualMethod就能夠實現子類對象調用父類方法的功能,如果想要調用一個對象的父類方法,而不是子類的方法的話,就可以使用CallNonvirtualMethod了,要使用它,首先要獲得父類及其要調用的父類方法的jmethodID,然后傳入到這個函數就能通過子類對象調用被覆寫的父類的方法了
例子:在Java中定義Father類:
packagecom.jni.demo;public classFather {public voidfunction(){
System.out.println("Father:function");
}
}
在定義一個子類Child:繼承Father類,從寫父類中的function方法
packagecom.jni.demo;public class Child extendsFather{
@Overridepublic voidfunction(){
System.out.println("Child:function");
}
}
在JNIDemo代碼:定義Father類型的屬性
packagecom.jni.demo;public classJNIDemo {public Father father = newChild();//定義一個本地方法
public native voidsayHello();public static voidmain(String[] args){//調用動態鏈接庫
System.loadLibrary("JNIDemo");
JNIDemo jniDemo= newJNIDemo();
jniDemo.sayHello();
}
}
在來看一下C++中的代碼:
#include#include"com_jni_demo_JNIDemo.h"JNIEXPORTvoid JNICALL Java_com_jni_demo_JNIDemo_sayHello (JNIEnv *env, jobject obj)
{//獲取obj中對象的class對象
jclass clazz = env->GetObjectClass(obj);//獲取Java中的father字段的id(最后一個參數是father字段的簽名)
jfieldID id_father = env->GetFieldID(clazz,"father","Lcom/jni/demo/Father;");//獲取father字段的對象類型
jobject father = env->GetObjectField(obj,id_father);//獲取father對象的class對象
jclass clazz_father = env->FindClass("com/jni/demo/Father");//獲取father對象中的function方法的id
jmethodID id_father_function = env->GetMethodID(clazz_father,"function","()V");//調用父類中的function方法(但是會執行子類的方法)
env->CallVoidMethod(father,id_father_function);//調用父類中的function方法(執行就是父類中的function方法)
env->CallNonvirtualVoidMethod(father,clazz_father,id_father_function);
}
Child:function是調用env->CallVoidMethod(...)方法的
Father:function是調用env->CallNonvirtualMethod(...)方法的
這樣就能夠控制到底調用哪個類的function方法了。
android jni 中jnienv,android JNI中JNIEnv類型和jobject類型的解釋相关推荐
- 利用JNI技术在Android中调用C++形式的OpenGL ES 2.0函数
1. 打开Eclipse,File-->New-->Project--->Android-->AndroidApplication Projec ...
- 利用JNI技术在Android中调用C++代码
JNI是Java Native Interface的简称,也就是Java本地接口,它提供了若干的API实现Java和其它语言的通信(主要是C&C++). 1.打开Eclipse,File--& ...
- 【Android 内存优化】Android 工程中使用 libjpeg-turbo 压缩图片 ( JNI 传递 Bitmap | 获取位图信息 | 获取图像数据 | 图像数据过滤 | 释放资源 )
文章目录 一.Bitmap 图像数据处理 二.Java 层 Bitmap 对象转为 JNI 层 bitmap 对象 三.获取 bitmap 中的图像数据 四.过滤 bitmap 中的图像数据 ( 获取 ...
- android中的jni两种注册时机 base/core/jni base/service/core/jni
https://www.jianshu.com/p/91321134207b 文章目录 1基本要点 2. android 中的jni 2.1Framework base/core/jni 机制 2.2 ...
- android studio 自动提示jni代码,如何将JNI(C/C++本机代码)添加到现有的Android Studio项目中...
从现有项目中执行以下步骤: 1.修改build.gradle(模块应用程序)看起来像这样(很多变化!): apply plugin: 'com.android.model.application' m ...
- 【Android 系统开发】Android JNI 之 JNIEnv 解析
. jni.h文件 : 了解 JNI 需要配合 jni.h 文件, jni.h 是 Google NDK 中的一个文件, 位置是 $/android-ndk-r9d/platforms/android ...
- Android JNI开发读取asserts目录中文件的方法
Android Java层读取asserts目录中的文件: //获取asserts/test/目录下的所有文件名称 String test_path = "test"; int c ...
- NDK JNI方式读写Android系统的demo(二)
NDK & JNI(方式读写Android系统的Demo) 大家都知道Android系统是一种基于Linux的自由及开放源码的操作系统,所以读写GPIO也可以直接用Linux那一套export ...
- 【Android NDK 开发】Kotlin 语言中使用 NDK ( 创建支持 Kotlin 的 NDK 项目 | Kotlin 语言中使用 NDK 要点 | 代码示例 )
文章目录 一.创建支持 Kotlin 的 NDK 项目 二.Kotlin 语言中使用 NDK 要点 1.加载动态库 2.声明 ndk 方法 3.Project 下的 build.gradle 配置 4 ...
最新文章
- [导入]实时数据库的经典书
- 十大Material Design开源项目
- 学习笔记--Spark
- 【Golang 接口自动化05】使用yml管理自动化用例
- 云小课 | 不小心删除了数据库,除了跑路还能咋办?
- Java集合——题目
- 【哈工大SCIR笔记】自然语言处理中的迁移学习(上)
- 宣传失真,二手人生。
- iOS OC和Swift相互引用,测试在swift项目
- java常见面试题:Java程序员面试题(四)
- 如何批量缩小图片尺寸大小?
- 统一资源定位符URL和统一资源标识符URI
- 通过表面分析评估 Cu-CMP 工艺
- html简单旋转木马
- 了解第四次工业革命带来的“机遇与挑战”
- Windows计算机操作系统基础知识点总结
- 01-初识sketch-sketch优势
- 视频直播之webp礼物解决方案
- Minio报错 The access key ID you provided does not exist in our records
- ubuntu搭建ftp后,winSCP连接报错为“列出’/home/ftp’的目录项时出错”
热门文章
- 病历智能处理引擎的架构设计、实现和应用
- ajax异步同步加载PHP代码,jquery中的ajax同步和异步详解
- python关键字中文意思_python 字符串只保留汉字的方法
- bash: telnet: command not found...
- flowable 表名sql mysql和oracle
- SpringBoot集成Editor.md 流程详细
- JBOSS7启动与关闭
- mysql malloc lib_CVE-2016-6662-MySQL ‘malloc_lib’变量重写命令执行分析 | CN-SEC 中文网...
- 中正则表达式详解_python :正则表达式/re库 超级详细de注释解释
- 逻辑回归预测事件发生的概率_通过逻辑回归,对信用卡申请数据使用卡方分箱法预测违约率建模...