- 浏览: 2204127 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (1240)
- mac/IOS (287)
- flutter (1)
- J2EE (115)
- android基础知识 (582)
- android中级知识 (55)
- android组件(Widget)开发 (18)
- android 错误 (21)
- javascript (18)
- linux (70)
- 树莓派 (18)
- gwt/gxt (1)
- 工具(IDE)/包(jar) (18)
- web前端 (17)
- java 算法 (8)
- 其它 (5)
- chrome (7)
- 数据库 (8)
- 经济/金融 (0)
- english (2)
- HTML5 (7)
- 网络安全 (14)
- 设计欣赏/设计窗 (8)
- 汇编/C (8)
- 工具类 (4)
- 游戏 (5)
- 开发频道 (5)
- Android OpenGL (1)
- 科学 (4)
- 运维 (0)
- 好东西 (6)
- 美食 (1)
最新评论
-
liangzai_cool:
请教一下,文中,shell、C、Python三种方式控制led ...
树莓派 - MAX7219 -
jiazimo:
...
Kafka源码分析-序列5 -Producer -RecordAccumulator队列分析 -
hp321:
Windows该命令是不是需要安装什么软件才可以?我试过不行( ...
ImageIO读jpg的时候出现javax.imageio.IIOException: Unsupported Image Type -
hp321:
Chenzh_758 写道其实直接用一下代码就可以解决了:JP ...
ImageIO读jpg的时候出现javax.imageio.IIOException: Unsupported Image Type -
huanghonhpeng:
大哥你真强什么都会,研究研究。。。。小弟在这里学到了很多知识。 ...
android 浏览器
在JNI调用中,肯定会涉及到本地方法操作Java类中数据和方法。在Java1.0中“原始的”Java到C的绑定中,程序员可以直接访问对象数据域。然而,直接方法要求虚拟机暴露他们的内部数据布局,基于这个原因,JNI要求程序员通过特殊的JNI函数来获取和设置数据以及调用java方法。
一、取得代表属性和方法的jfieldID和jmethodID
为了在C/C++中表示属性和方法,JNI在jni.h头文件中定义了jfieldID和jmethodID类型来分别代表Java端的属性和方法。我们在访问或是设置Java属性的时候,首先就要先在本地代码取得代表该Java属性的jfieldID,然后才能在本地代码进行Java属性操作。同样的,我们需要调用Java端的方法时,也是需要取得代表该方法的jmethodID才能进行Java方法调用。
使用JNIEnv提供的JNI方法,我们就可以获得属性和方法相对应的jfieldID和jmethodID:
下面看这个方法的原型
可以看到这四个方法的参数列表都是一模一样的,下面来分析下每个参数的含义:
第一个参数jclass clazz :
上篇讲到jclass,相当于Java中的Class类,代表一个Java类,而这里面的代表的就是我们操作的Class类,我们要从这个类里面取的属性和方法的ID。
第二个参数const char *name
这是一个常量字符数组,代表我们要取得的方法名或者变量名。
第三个参数const char *sig
这也是一个常量字符数组,代表我们要取得的方法或变量的 签名。
什么是方法或者变量的签名呢?
看下面的例子:
下面的类中,有一个本地方法,和两个重载的show方法。
那么,我们在本地方法中调用其中的某一个show方法:
那这样取得的jmethodID到底是哪个show方法呢?所以这就是第三个参数sig的作用,sig其实是单词sign的缩写,它用于指定要取得的属性或方法的类型。
这里的sig如果指定为"(I)V",则返回void show(int)方法的jmethodID。如果指定为"(D)V",则返回void show(double)方法的jmethodID。
如何签名:
下面看看Sign签名如何写,来表示要取得的属性或方法的类型。
1、普通类型签名
boolean Z
byte B
char C
short S
int I
long L
float F
double D
void V
2、引用类型签名
object L开头,然后以/ 分隔包的完整类型,后面再加; 比如说String 签名就是 Ljava/lang/String;
Array 以[ 开头,在加上数组元素类型的签名 比如int[] 签名就是[I ,在比如int[][] 签名就是[[I ,object数组签名就是[Ljava/lang/Object;
3、方法签名
(参数1类型签名 参数2类型签名 参数3类型签名 .......)返回值类型签名
还要注意,就算java构造器没返回值,也加上V签名
由于签名比较难以记忆,JDK提供了一个工具javap来查看一个类的声明。其中就可以设置输出每个方法/属性的签名。
javap -s <options> className
-s 表示是签名
options 可以使-private -protected -public 用于选择性的输出private 或protected 或 public声明的方法/属性。
二、根据获取的ID,来取得和设置属性,以及调用方法。
取得了代表属性和方法的ID,就可以利用JNIEnv提供的方法来进行下一步的操作了。
1、如何获得和设置属性/静态属性
取得了代表属性和静态属性的jfieldID,就可以用在JNIEnv中提供的一系列的方法,来获取和设置属性/静态属性。
获取的形式如下:Get<Type>Field GetStatic<Type>Field。
设置的形式如下:Set<Type>Field SetStatic<Type>Field。
比如:取得属性:
比如:取得静态属性:
Get方法的第一个参数代表要获取的属性的对象或者jclass对象,第二个参数即属性的ID
比如;设置属性:
比如;设置静态属性:
Set方法的第一个参数代表要设置的属性的对象或者jclass对象,第二个参数即属性的ID,第三个参数代表要设置的值。
2、如何调用方法
取得了代表方法和静态方法的jmethodID,就可以用在JNIEnv中提供的一系列的方法,来调用方法和静态方法。
有三种形式来调用方法和静态方法:
普通方法:
静态方法:
这里面的Type也和上面获取和设置属性的Type一样,表示各种类型,如Int,Char,Byte等等,这里面的Type代表的是这个方法的返回值类型。
第一个参数代表调用的这个方法属于哪个对象,或者这个静态方法属于哪个类。
第二个参数代表jmethodID。
后面的参数,就代表这个方法的参数列表了。只不过有3中方式来设置这个参数列表。
下面来详细说明如何通过这3个方法来设置参数列表(以非静态方法举例,静态方法和的设置一致)。
方式1、Call<Type>Method(jobject obj, jmethodID methodID,...)
用不定参数的形式来一个个指定对应的参数列表。比如有这么一个Java方法
通过这个方法,要这样设置参数列表:
方式2、Call<Type>MethodV(jobject obj, jmethodID methodID,va_list args)
这种方式使用很少。
方式三:Call<Type>MethodA(jobject obj, jmethodID methodID,jvalue* v)
第三种传参的形式是传入一个jvalue的指针。jvalue类型是在 jni.h头文件中定义的联合体union,看它的定义:
联合体可以储存不同类型的变量,但是一个联合体对象只能存储它里面定义的某一个类型的变量。
所以这里要传入一系列参数,要使用jvalue数组或者指针。
例子:
静态方法 的使用也是类似的形式。
三、如何调用子类重写的父类方法
在Java:
这里调用的是Son的show方法,而不是Father的show方法,这就是java的多态。
但是在C++中,
这里,调用的却是父类的show方法。
这是因为C++和Java的多态的不一样的地方,只有当一个父类的方法被声明为virtual——虚函数的时候,才能被子类覆盖,才能实现多态。
而Java默认实现了这一点,Java类中的所有成员方法都是虚函数。所以能够直接实现多态,但是C++中的不同,必须我们自己加上关键字virtual。
所以,如果把上面的C++代码改成如下形式,就可以实现和Java一样的效果:
那么,在JNI中,我们可不可以通过子类的对象,去调用父类被子类重写的方法呢?我们知道,在Java中是不可以的,最多只能在重写该方法的时候,使用super调用一下,但是在其他的地方就可以调用了。但是我们在JNI中,却可以实现子类调用父类被重写的方法。 这也是为了让JNI的本地方法更加贴近C/C++的特性。
要想实现子类调用父类被重写的方法,要使用JNIEnv提供的一系列方法。形式如下:
CallNonvirtual<Type>Method(jobject obj, jclass clazz,jmethodID methodID, ...)
CallNonvirtual<Type>MethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args)
CallNonvirtual<Type>MethodA(jobject obj, jclass clazz,jmethodID methodID, const jvalue * args)
Type就是表示这个方法的返回类型,如Object、Boolean、Int。再看方法参数的含义:
第一个参数 jobject obj 代表的子类的对象
第二个参数jclass clazz 代表的是父类的jclass对象
第三个参数jmethodID methodID 代表的是父类中 被子类重写的方法的ID(也就是父类方法的ID,而不是子类的)。
后面的参数都是指定方法的参数列表,这和上面讲到的方法调用一样的。
下面看看使用实例:
有这样一段Java代码。
在上面的Java代码中,有一个父类Father,和一个子类的Son方法,然后有一个本地方法show。
下面,我们来书写我们的本地方法show。
输出结果为
Son
Father
android职业交流QQ 群,有兴趣的可以一起来多搞搞技术、职业交流,互相学习、提高,互通好的职业信息,群号:104286694
一、取得代表属性和方法的jfieldID和jmethodID
为了在C/C++中表示属性和方法,JNI在jni.h头文件中定义了jfieldID和jmethodID类型来分别代表Java端的属性和方法。我们在访问或是设置Java属性的时候,首先就要先在本地代码取得代表该Java属性的jfieldID,然后才能在本地代码进行Java属性操作。同样的,我们需要调用Java端的方法时,也是需要取得代表该方法的jmethodID才能进行Java方法调用。
使用JNIEnv提供的JNI方法,我们就可以获得属性和方法相对应的jfieldID和jmethodID:
- GetFieldID :取得成员变量的id
- GetStaticFieldID :取得静态成员变量的id
- GetMethodID :取得方法的id
- GetStaticMethodID :取得静态方法的id
下面看这个方法的原型
jfieldID GetFieldID(jclass clazz, const char *name, const char *sig) jfieldID GetStaticFieldID(jclass clazz, const char *name, const char *sig) jmethodID GetStaticMethodID(jclass clazz, const char *name, const char *sig) jmethodID GetMethodID(jclass clazz, const char *name,const char *sig)
可以看到这四个方法的参数列表都是一模一样的,下面来分析下每个参数的含义:
第一个参数jclass clazz :
上篇讲到jclass,相当于Java中的Class类,代表一个Java类,而这里面的代表的就是我们操作的Class类,我们要从这个类里面取的属性和方法的ID。
第二个参数const char *name
这是一个常量字符数组,代表我们要取得的方法名或者变量名。
第三个参数const char *sig
这也是一个常量字符数组,代表我们要取得的方法或变量的 签名。
什么是方法或者变量的签名呢?
看下面的例子:
下面的类中,有一个本地方法,和两个重载的show方法。
public class NativeTest { public native void showNative(); public void show(int i){ System.out.println(i); } public void show(double d){ System.out.println(d); } }
那么,我们在本地方法中调用其中的某一个show方法:
jclass clazz_NativeTest=env->FindClass("cn/itcast/NativeTest"); //取得jmethodID jmethodID id_show=env->GetMethodID(clazz_NativeTest,“show”,"???");
那这样取得的jmethodID到底是哪个show方法呢?所以这就是第三个参数sig的作用,sig其实是单词sign的缩写,它用于指定要取得的属性或方法的类型。
这里的sig如果指定为"(I)V",则返回void show(int)方法的jmethodID。如果指定为"(D)V",则返回void show(double)方法的jmethodID。
如何签名:
下面看看Sign签名如何写,来表示要取得的属性或方法的类型。
1、普通类型签名
boolean Z
byte B
char C
short S
int I
long L
float F
double D
void V
2、引用类型签名
object L开头,然后以/ 分隔包的完整类型,后面再加; 比如说String 签名就是 Ljava/lang/String;
Array 以[ 开头,在加上数组元素类型的签名 比如int[] 签名就是[I ,在比如int[][] 签名就是[[I ,object数组签名就是[Ljava/lang/Object;
3、方法签名
(参数1类型签名 参数2类型签名 参数3类型签名 .......)返回值类型签名
还要注意,就算java构造器没返回值,也加上V签名
由于签名比较难以记忆,JDK提供了一个工具javap来查看一个类的声明。其中就可以设置输出每个方法/属性的签名。
javap -s <options> className
-s 表示是签名
options 可以使-private -protected -public 用于选择性的输出private 或protected 或 public声明的方法/属性。
二、根据获取的ID,来取得和设置属性,以及调用方法。
取得了代表属性和方法的ID,就可以利用JNIEnv提供的方法来进行下一步的操作了。
1、如何获得和设置属性/静态属性
取得了代表属性和静态属性的jfieldID,就可以用在JNIEnv中提供的一系列的方法,来获取和设置属性/静态属性。
获取的形式如下:Get<Type>Field GetStatic<Type>Field。
设置的形式如下:Set<Type>Field SetStatic<Type>Field。
比如:取得属性:
jobject GetObjectField(jobject obj, jfieldID fieldID) jboolean GetBooleanField(jobject obj, jfieldID fieldID) jbyte GetByteField(jobject obj, jfieldID fieldID)
比如:取得静态属性:
jobject GetStaticObjectField(jclass clazz, jfieldID fieldID) jboolean GetStaticBooleanField(jclass clazz, jfieldID fieldID) jbyte GetStaticByteField(jclass clazz, jfieldID fieldID)
Get方法的第一个参数代表要获取的属性的对象或者jclass对象,第二个参数即属性的ID
比如;设置属性:
void SetObjectField(jobject obj, jfieldID fieldID, jobject val) void SetBooleanField(jobject obj, jfieldID fieldID,jboolean val) void SetByteField(jobject obj, jfieldID fieldID, jbyte val)
比如;设置静态属性:
void SetStaticObjectField(jobject obj, jfieldID fieldID, jobject val) void SetStaticBooleanField(jobject obj, jfieldID fieldID,jboolean val) void SetStaticByteField(jobject obj, jfieldID fieldID, jbyte val)
Set方法的第一个参数代表要设置的属性的对象或者jclass对象,第二个参数即属性的ID,第三个参数代表要设置的值。
2、如何调用方法
取得了代表方法和静态方法的jmethodID,就可以用在JNIEnv中提供的一系列的方法,来调用方法和静态方法。
有三种形式来调用方法和静态方法:
普通方法:
Call<Type>Method(jobject obj, jmethodID methodID,...) Call<Type>MethodV(jobject obj, jmethodID methodID,va_list args) Call<Type>tMethodA(jobject obj, jmethodID methodID,const jvalue *args)
静态方法:
CallStatic<Type>Method(jclass clazz, jmethodID methodID,...) CallStatic<Type>MethodV(jclass clazz, jmethodID methodID,va_list args) CallStatic<Type>tMethodA(jclass clazz, jmethodID methodID,const jvalue *args)
这里面的Type也和上面获取和设置属性的Type一样,表示各种类型,如Int,Char,Byte等等,这里面的Type代表的是这个方法的返回值类型。
第一个参数代表调用的这个方法属于哪个对象,或者这个静态方法属于哪个类。
第二个参数代表jmethodID。
后面的参数,就代表这个方法的参数列表了。只不过有3中方式来设置这个参数列表。
下面来详细说明如何通过这3个方法来设置参数列表(以非静态方法举例,静态方法和的设置一致)。
方式1、Call<Type>Method(jobject obj, jmethodID methodID,...)
用不定参数的形式来一个个指定对应的参数列表。比如有这么一个Java方法
public int show(int i,double d,char c){ 。。。。 }
通过这个方法,要这样设置参数列表:
jint i=10L; jdouble d=2.4; jchar c=L'd'; env->CallIntMethod(obj,id_show,i,d,c);
方式2、Call<Type>MethodV(jobject obj, jmethodID methodID,va_list args)
这种方式使用很少。
方式三:Call<Type>MethodA(jobject obj, jmethodID methodID,jvalue* v)
第三种传参的形式是传入一个jvalue的指针。jvalue类型是在 jni.h头文件中定义的联合体union,看它的定义:
typedef union jvalue { jboolean z; jbyte b; jchar c; jshort s; jint i; jlong j; jfloat f; jdouble d; jobject l; } jvalue;
联合体可以储存不同类型的变量,但是一个联合体对象只能存储它里面定义的某一个类型的变量。
所以这里要传入一系列参数,要使用jvalue数组或者指针。
例子:
jvalue * args=new jvalue[3]; args[0].i=12L; args[1].d=1.2; args[2].c=L'c'; jmethodID id_goo=env->GetMethodID(env->GetObjectClass(obj),"goo","(IDC)V"); env->CallVoidMethodA(obj,id_goo,args); delete [] args; //释放内存
静态方法 的使用也是类似的形式。
三、如何调用子类重写的父类方法
在Java:
class Father{ public void show(){ System.out.println("Father"); } } class Son extends Father{ @Override public void show() { System.out.println("Son"); } }
public static void main(String[] args) { Father father=new Son(); father.show(); }
这里调用的是Son的show方法,而不是Father的show方法,这就是java的多态。
但是在C++中,
class Father{ public: void show(){ cout<<"Father"<<endl; } }; class Son:public Father{ public : void show(){ cout<<"Son"<<endl; } };
Father* father=new Son(); father->show();
这里,调用的却是父类的show方法。
这是因为C++和Java的多态的不一样的地方,只有当一个父类的方法被声明为virtual——虚函数的时候,才能被子类覆盖,才能实现多态。
而Java默认实现了这一点,Java类中的所有成员方法都是虚函数。所以能够直接实现多态,但是C++中的不同,必须我们自己加上关键字virtual。
所以,如果把上面的C++代码改成如下形式,就可以实现和Java一样的效果:
class Father{ public: virtual void function(){ cout<<"Father"<<endl; } }; class Son:public Father{ public : void function(){ cout<<"Son"<<endl; } };
那么,在JNI中,我们可不可以通过子类的对象,去调用父类被子类重写的方法呢?我们知道,在Java中是不可以的,最多只能在重写该方法的时候,使用super调用一下,但是在其他的地方就可以调用了。但是我们在JNI中,却可以实现子类调用父类被重写的方法。 这也是为了让JNI的本地方法更加贴近C/C++的特性。
要想实现子类调用父类被重写的方法,要使用JNIEnv提供的一系列方法。形式如下:
CallNonvirtual<Type>Method(jobject obj, jclass clazz,jmethodID methodID, ...)
CallNonvirtual<Type>MethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args)
CallNonvirtual<Type>MethodA(jobject obj, jclass clazz,jmethodID methodID, const jvalue * args)
Type就是表示这个方法的返回类型,如Object、Boolean、Int。再看方法参数的含义:
第一个参数 jobject obj 代表的子类的对象
第二个参数jclass clazz 代表的是父类的jclass对象
第三个参数jmethodID methodID 代表的是父类中 被子类重写的方法的ID(也就是父类方法的ID,而不是子类的)。
后面的参数都是指定方法的参数列表,这和上面讲到的方法调用一样的。
下面看看使用实例:
有这样一段Java代码。
package com.tao.test; public class Test { private Son son=new Son(); public native void show(); static{ System.loadLibrary("NativeTest"); } public static void main(String[] args) { new Test().show(); } } class Father{ public void function(){ System.out.println("Father"); } } class Son extends Father{ @Override public void function() { System.out.println("Son"); } }
在上面的Java代码中,有一个父类Father,和一个子类的Son方法,然后有一个本地方法show。
下面,我们来书写我们的本地方法show。
JNIEXPORT void JNICALL Java_com_tao_test_Test_show (JNIEnv * env, jobject obj) { //首先取得Test类中son属性的ID jfieldID id_son=env->GetFieldID(env->GetObjectClass(obj),"son","Lcom/tao/test/Son;"); //取得son属性 jobject son=env->GetObjectField(obj,id_son); //先看调用子类的show方法 //取得子类的show方法的id,然后调用子类的show方法 jmethodID id_show=env->GetMethodID(env->GetObjectClass(son),"function","()V"); env->CallVoidMethod(son,id_show); //再看如果调用父类中被重写的方法 //取得父类Father的jclass对象 jclass clazz_father=env->FindClass("com/tao/test/Father") //取得父类中show方法的id jmethodID id_show_father=env->GetMethodID(clazz_father,"function","()V"); //调用CallNonvirtual<Type>Method方法调用父类中被重写的方法 env->CallNonvirtualVoidMethod(son,env->FindClass("com/tao/test/Father"),id_show_father); }
输出结果为
Son
Father
android职业交流QQ 群,有兴趣的可以一起来多搞搞技术、职业交流,互相学习、提高,互通好的职业信息,群号:104286694
发表评论
-
jni未释放资源问题。Failed adding to JNI local ref table (has 512 entries)
2016-02-01 14:51 983Native Code 本身的内存泄漏 JNI 编程首先是一 ... -
android ApkPlug使用
2015-12-09 15:14 734直接下载附件吧, 有两个是官方的demo包,还有一个是他们技术 ... -
dynamic-load-apk-Apk动态加载框架使用初体验
2015-12-03 10:40 799因为想要将本网站上的开源代码直接做成一个能显示效果的app,决 ... -
Android动态加载进阶 代理Activity模式
2015-11-30 17:20 885技术背景 简单模式中 ... -
Android NDK rb5 文档之本地活动和应用程序
2015-11-24 22:34 816Native Activities and Applicati ... -
Android NDK rb5 文档之 native_activity.h 文件翻译
2015-11-24 22:30 1010/** * Copyright (C) 2010 The A ... -
Android新技术学习——阿里巴巴免Root无侵入AOP框架Dexposed
2015-11-21 13:49 1793引用阿里巴巴无线事业部最近开源的Android平台下的无侵入运 ... -
Android NDK开发之JNI基础知识
2015-11-21 13:05 1128JAVA层与JNI层数据类型的对应 下面是一个测试方法 pu ... -
ANDROID2.2 JNI 配置luajit2
2015-11-21 11:18 744去http://luajit.org/官网下载最新的版本 在 ... -
在Android平台上加载本地库的危险性[转]
2015-11-13 09:30 1588在2012年KeepSafe的创业初期,我们试图找到一种为An ... -
JNI: 能否用 GetFieldID()/GetStaticFieldID()取得enum变量的属性?
2015-11-06 11:52 1846没有问题的,jni下面一样可以动态获取的 仅供参考! VOI ... -
ndk-stack定位不出崩溃代码行的问题
2015-10-30 08:51 1250NDK开发包中自带的NDK-STACK工具是可以查看崩溃栈信息 ... -
Android.mk文件详解
2015-10-27 09:23 1843Android.mk是Android提供的 ... -
NDK在增加断点时跳不进去,不管用的解决办法
2015-10-26 10:09 1106先看下面的错,如果报的不是这个那就不是我这个问题,那就不用再看 ... -
插件化的基石 -- apk动态加载
2015-09-25 09:13 971Android动态加载技术在蘑菇街的第一次实践,还是在14年的 ... -
warning:deprecated conversion from string constant to 'char *' 解决方案
2015-09-25 09:01 1857char* createClass(){ ret ... -
jni内存释放
2015-09-24 12:03 3677调用GetStringUTFChars,GetDoubleAr ... -
如何不要让ndk-build自动删除.so
2015-08-04 15:33 1175在用ndk-build的时候突然发现在编译完成之后会自动删除a ... -
超简单的NDK单步调试方法
2015-08-03 21:19 603最近为了性能需求,开始搞JNI,白手起搞真心不容易。中间差点崩 ... -
[转]Android JNI层实现文件的read、write与seek操作
2015-08-03 14:41 12551、 在Andr ...
相关推荐
这就是在JNI中调用Java静态方法的基本流程。需要注意的是,由于JNI涉及到跨语言交互,因此在处理字符串、数组等复杂数据类型时,需要特别注意类型转换和内存管理。此外,由于每次Java类加载时都会执行静态初始化代码...
在本文中,我们将深入探讨如何在Visual Studio 2019环境下使用C++通过Java Native Interface (JNI)来调用Java代码。JNI是Java平台的一部分,它为Java应用程序提供了与本地代码交互的能力,使得开发者可以将Java应用...
在提供的资源"使用C++创建java虚拟机JVM,使用JNI调用java函数"中,可能详细介绍了以上步骤的实际应用,包括代码示例和可能遇到的问题及解决方案。通过学习和实践这个教程,开发者可以更好地理解和掌握C++与Java之间...
现在,Java程序就可以通过JNI调用C/C++实现的本地方法了,同时,你也可以在本地代码中通过JNI访问和调用Java类的方法和构造函数。 通过JNI,开发者可以在Java和C/C++之间自由地传递数据、调用方法,甚至创建新的...
### 二、JNI调用Java类的具体步骤 #### 1. 准备阶段 首先,我们需要一个简单的Java程序,例如上述例子中的`Prog.java`。这个程序定义了一个静态方法`main`,它接收一个字符串数组参数,并输出一段包含参数信息的...
使用`GetMethodId`函数获取Java方法的ID,这个ID是JNI调用Java方法的关键。函数接受三个参数:JNIEnv指针,类的引用(`jclass`),以及方法名和方法签名的字符串。方法签名描述了方法的参数类型和返回类型,如`"()V...
在这个例子中,`JNIEnv *env`参数提供了访问Java对象和调用Java方法的能力。`jobject`参数代表Java对象实例,但由于我们是在静态方法中,所以通常用作注释。`Java_com_example_ndkdemo3_MainActivity_stringFromJNI`...
1. **调用Java静态方法** 要调用Java的静态方法,我们首先需要通过`LoadLibrary`函数加载包含该方法的Java类,然后通过`FindClass`获取类的JNI描述符,再使用`GetStaticMethodID`获取静态方法的ID。最后,使用`...
在上述示例中,我们看到`JniTest`类的实例方法和静态方法都被调用了。例如,`jni.PrintHello()`将调用C++中的`Java_JniTest_PrintHello()`,`jni.PrintArray(arr)`则会调用`Java_JniTest_TestArray()`,并将数组`arr...
JNI调用Java静态属性的步骤大致如下: 1. 获取Java类对象:和非静态属性类似,使用`GetObjectClass`函数获取目标Java对象所属的类对象。 2. 获取静态字段ID:使用`GetStaticFieldID`函数根据字段名和类型签名获取...
标题中的“JNI调用IE,延迟一段时间关闭”指的是在Java程序中通过JNI(Java Native Interface)技术调用本地系统资源,比如Internet Explorer浏览器,并且在指定的时间延迟后自动关闭浏览器。这种技术通常用于自动化...
JNI实现java cpp相互调用,包括动态注册和静态注册两种方式,具体包含 静态方式实现: C/C++中访问Java方法 C/C++中访问Java父类的方法 C/C++中访问/修改Java变量 Java中访问C/C++方法 Java中访问/修改C/C++变量 ...
`JNIEnv`提供了多种方法来获取Java类、对象、字段ID和方法ID。 - 获取Java类:`jclass FindClass(const char *name)`,其中`name`是类的全名,包括包名。 - 获取对象:`jobject GetObjectClass(JNIEnv *env, ...
通过JNI调用第三方动态库在Android开发中是常见操作,涉及到的知识点包括Java本地方法声明、JNI接口定义、Makefile编写以及NDK编译。在实际操作过程中,务必注意代码的正确性,因为一个小错误都可能导致编译失败或...
在本教程中,我们将深入探讨如何在Java程序中通过JNI调用Visual Studio 2005(VS2005)编译的C++代码。这个过程包括几个关键步骤,包括创建C++库、编写Java的JNI接口、编译C++代码以及在Java程序中加载和调用本地...
JNI接口定义了一组函数和数据类型,使得Java代码能够声明并调用本地方法(即非Java代码),同时本地方法也能调用Java代码。这通常涉及到以下步骤: 1. **编写Java代码**:在Java类中声明native方法,该方法没有具体...
在易语言中,使用JNI调用Java方法的步骤大致如下: 1. **导入Java库**:在易语言程序中,首先需要导入包含所需Java类的库,这通常是通过JNI的`LoadLibrary`函数完成的。 2. **查找Java方法**:使用`FindClass`找到...
5. **加载并调用本地库**:在Java代码中通过`System.loadLibrary`方法加载本地库,并调用之前声明的本地方法。 #### 三、环境配置 为了实现JNI,需要准备以下环境: 1. **Android NDK**:包含完整的Android编译器...
JNI接口提供了调用Java方法、创建和操作Java对象以及访问Java字段的功能。 2. **Java类字段**: 在Java中,类字段是类的成员变量,它们可以是静态的或非静态的,可以有默认值或初始化器。在JNI中,我们可以直接...
在JNI中,可以通过`FindClass`, `GetStaticFieldID`和`GetStatic*Field`(或`SetStatic*Field`)方法来获取和修改Java类的静态字段。 6. **线程安全**:在Android 5.0中,JNI函数默认运行在主线程之外,开发者需要...