转自: http://blog.csdn.net/jiangwei0910410003/article/details/17466369  

上一篇说道JNIEnv中的方法的用法,这一篇我们就来通过例子来看一下这些方法的使用:

首先是第一个例子:在Java代码中定义一个属性,然后再C++代码中将其设置成另外的值,并且输出来

先来看一下Java代码:

  1. package com.jni.demo;
  2. public class JNIDemo {
  3. public int number = 0;//定义一个属性
  4. //定义一个本地方法
  5. public native void sayHello();
  6. public static void main(String[] args){
  7. //调用动态链接库
  8. System.loadLibrary("JNIDemo");
  9. JNIDemo jniDemo = new JNIDemo();
  10. jniDemo.sayHello();
  11. System.out.print(jniDemo.number);
  12. }
  13. }

在来看一下C++代码:

  1. #include<iostream.h>
  2. #include "com_jni_demo_JNIDemo.h"
  3. JNIEXPORT void JNICALL Java_com_jni_demo_JNIDemo_sayHello (JNIEnv * env, jobject obj)
  4. {
  5. //获取obj中对象的class对象
  6. jclass clazz = env->GetObjectClass(obj);
  7. //获取Java中的number字段的id(最后一个参数是number的签名)
  8. jfieldID id_number = env->GetFieldID(clazz,"number","I");
  9. //获取number的值
  10. jint number = env->GetIntField(obj,id_number);
  11. //输出到控制台
  12. cout<<number<<endl;
  13. //修改number的值为100,这里要注意的是jint对应C++是long类型,所以后面要加一个L
  14. env->SetIntField(obj,id_number,100L);
  15. }

编译成功后,在Eclipse运行后的结果:

第一个0是在C++代码中的cout<<number<<endl;

第二个100是在Java中的System.out.println(jniDemo.number);

JNIEnv提供了众多的Call<Type>Method和CallStatic<Type>Method,还有CallNonvirtual<Type>Method函数,需要通过GetMethodID取得相应方法的jmethodID来传入到上述函数的参数中

调用示例方法的三种形式:

Call<Type>Method(jobject obj,jmethodID id,....);

Call<Type>Method(jobject obj,jmethodID id,va_list lst);

Call<Type>Method(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;
}

这时候用javap获取max方法的签名:

max方法的签名是(DD)D

在C++中的代码:

  1. JNIEXPORT void JNICALL Java_com_jni_demo_JNIDemo_sayHello (JNIEnv * env, jobject obj)
  2. {
  3. //获取obj中对象的class对象
  4. jclass clazz = env->GetObjectClass(obj);
  5. //获取Java中的max方法的id(最后一个参数是max方法的签名)
  6. jmethodID id_max = env->GetMethodID(clazz,"max","(DD)D");
  7. //调用max方法
  8. jdouble doubles = env->CallDoubleMethod(obj,id_max,1.2,3.4);
  9. //输出返回值
  10. cout<<doubles<<endl;
  11. }

编译成动态文件后到Eclipse中执行sayHello方法,运行结果如下:

成功的输出了最大值

JNIEnv中有一个特殊的方法:CallNonvirtual<Type>Method方法

首先来了解一下上面调用的function是子类的function方法,这个我们都知道,但是在C++中就不一样了:

这段C++代码中执行的是父类的function方法,那如果想执行子类的function方法怎么办呢?那就需要将父类的function方法定义成virtual虚函数:

所以说C++和Java对于继承后执行的是父类的还是子类的方法是有区别的,在Java中所有的方法都是virtual的,所以总是调用子类的方法,所以CallNonVirtual<Type>Method这个方法就出来了,这个方法就可以帮助我们调用Java中的父类的方法:

在JNI中定义的CallNonvirtual<Type>Method就能够实现子类对象调用父类方法的功能,如果想要调用一个对象的父类方法,而不是子类的方法的话,就可以使用CallNonvirtual<Type>Method了,要使用它,首先要获得父类及其要调用的父类方法的jmethodID,然后传入到这个函数就能通过子类对象调用被覆写的父类的方法了

例子:在Java中定义Father类:

  1. package com.jni.demo;
  2. public class Father {
  3. public void function(){
  4. System.out.println("Father:function");
  5. }
  6. }

在定义一个子类Child:继承Father类,从写父类中的function方法

  1. package com.jni.demo;
  2. public class Child extends Father{
  3. @Override
  4. public void function(){
  5. System.out.println("Child:function");
  6. }
  7. }

在JNIDemo代码:定义Father类型的属性

  1. package com.jni.demo;
  2. public class JNIDemo {
  3. public Father father = new Child();
  4. //定义一个本地方法
  5. public native void sayHello();
  6. public static void main(String[] args){
  7. //调用动态链接库
  8. System.loadLibrary("JNIDemo");
  9. JNIDemo jniDemo = new JNIDemo();
  10. jniDemo.sayHello();
  11. }
  12. }

在来看一下C++中的代码:

  1. #include<iostream.h>
  2. #include "com_jni_demo_JNIDemo.h"
  3. JNIEXPORT void JNICALL Java_com_jni_demo_JNIDemo_sayHello (JNIEnv * env, jobject obj)
  4. {
  5. //获取obj中对象的class对象
  6. jclass clazz = env->GetObjectClass(obj);
  7. //获取Java中的father字段的id(最后一个参数是father字段的签名)
  8. jfieldID id_father = env->GetFieldID(clazz,"father","Lcom/jni/demo/Father;");
  9. //获取father字段的对象类型
  10. jobject father = env->GetObjectField(obj,id_father);
  11. //获取father对象的class对象
  12. jclass clazz_father = env->FindClass("com/jni/demo/Father");
  13. //获取father对象中的function方法的id
  14. jmethodID id_father_function = env->GetMethodID(clazz_father,"function","()V");
  15. //调用父类中的function方法(但是会执行子类的方法)
  16. env->CallVoidMethod(father,id_father_function);
  17. //调用父类中的function方法(执行就是父类中的function方法)
  18. env->CallNonvirtualVoidMethod(father,clazz_father,id_father_function);
  19. }

编译成功.dll文件,回到Eclipse中运行结果如下:

Child:function是调用env->CallVoidMethod(...)方法的

Father:function是调用env->CallNonvirtualMethod(...)方法的

这样就能够控制到底调用哪个类的function方法了。

最新文章

  1. 求1...n中因子最多的数
  2. linux 查找文件或者内容常用命令
  3. Linux gnome
  4. 10. 将摄像机对准物体,并显示整个对准过程,摄像机Zoom
  5. WEB 3D SVG CAD 向量 几个实施
  6. 【HELLO WAKA】WAKA iOS客户端 之二 架构设计与实现篇
  7. TargetType Mismatch
  8. 深入浅出WPF——附加事件(Attached Event)
  9. 消息中间件ActiveMQ及Spring整合JMS的介绍
  10. 拦截窗体关闭、最大、最小事件 - Winform
  11. GC真正的垃圾:强、软、弱、和虚 对象
  12. MyBatis Generator For Eclipse 插件安装
  13. Oracle查询数据库中所有表的记录数
  14. MongoDB 常用的几大GUI工具
  15. zookeeper-01 概述
  16. Hive日志(Hive Logging)--hive GettingStarted翻译
  17. [Writeup]奇怪的单点音
  18. jsp----标签编程(JSTL)
  19. standard cell timing model
  20. BZOJ5294 BJOI2018二进制(线段树)

热门文章

  1. 2基本类型数组和枚举类型——重拾Java
  2. canvas 移动光速特效-
  3. java script btoa与atob的
  4. Swagger与SpringMVC整合
  5. web项目生成web.xml的两种方式
  6. Ubuntu中解决机箱前置耳机没声音
  7. python 的时间与日期
  8. oracle 使用正则表达式获取字符串中包含的数字
  9. Notepad++正则表达式格式 Editplus使用正则表达式[转]
  10. IBM关闭触摸板的方法