Jni接口-深入研究参数的传递(一)

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Jni接⼝-深⼊研究参数的传递(⼀)
在上⼀个随笔中介绍了怎样实现⼀个简单的Jni⼩程序。

在这⼀篇⾥主要是说⼀下JAVA与C++之间的参数传递问题。

本⼈是个Java程序员,⼯作没⼏年菜鸟级别,C++不是很熟悉,但对.NET到是了解⼀些,所以这⾥⾯的C++部分都⽤C++.net来讲的。

为了便于理解,⽂档中可能会有很多通俗易懂的⽩话,最近也是项⽬中⽤到了Jni 才学习了⼏天,所以这⾥要是有哪说得不对,还请⼤家见谅,发现问题就指出来,⼤家⼀起学习哈!
先⼤致回顾下上⼀篇的内容,在上⼀篇⾥我们创建了⼀个JAVA类Test.java和C++.net的Jin01项⽬。

主要是实现Jin01中输出“第⼀个Jni ⼩程序”,然后⽤Test.java来调⽤。

(详情请见上⼀篇内容)
Jni01中的函数是:
#include "stdafx.h"
#include "WINSCARD.H"
#include "com_test01_Test.h"
using namespace System;
int main(array<System::String ^> ^args) {
Console::WriteLine(L"Hello World");
return 0;
}
//实现Java_com_test01_Test_firstTest⽅法
JNIEXPORT void JNICALL Java_com_test01_Test_firstTest(JNIEnv *, jobject){
Console::WriteLine(L"第⼀个Jni⼩程序");
}
Test.java代码如下:
public class Test {
public native void firstTest();//
public static void main(String[] args) {
System.loadLibrary("Jni01");
Test t=new Test();
t.firstTest();
}
}
1、com_test01_Test.h头⽂件中实现Jni接⼝⽅法深⼊研究
在上⼀篇的例⼦中实现Jni接⼝的⽅法声明在com_test01_Test.h头⽂件中,代码如下:(以下按照字体颜⾊来解释每个部分的意思)
JNIEXPORT void JNICALL Java_com_test01_Test_firstTest (JNIEnv * env, jobject obj);
(1)JNIEXPORT:在Jni编程中所有本地语⾔实现Jni接⼝的⽅法前⾯都有⼀个"JNIEXPORT",这个可以看做是Jni的⼀个标志,⾄今为⽌没发现它有什么特殊的⽤处。

(2)void:这个学过编程的⼈都知道,当然是⽅法的返回值了。

(3)JNICALL:这个可以理解为Jni 和Call两个部分,和起来的意思就是 Jni调⽤XXX(后⾯的XXX就是JAVA的⽅法名)。

(4)Java_com_test01_Test_firstTest:这个就是被上⼀步中被调⽤的部分,也就是Java中的native ⽅法名,这⾥起名字的⽅式⽐较特别,是:包名+类名+⽅法名。

(5)JNIEnv * env:这个env可以看做是Jni接⼝本⾝的⼀个对象,在上⼀篇中提到的jni.h头⽂件中存在着⼤量被封装好的函数,这些函数也是Jni编程中经常被使⽤到的,要想调⽤这些函数就需要使⽤JNIEnv这个对象。

例如:env->GetObjectClass()。

(详情请查看jni.h)
(6)jobject obj:刚才在Test类的main⽅法中有这样⼀段代码: 
Test t=new Test(); t.firstTest();
这个jobject需要两种情况分析。

上段代码中firstTest⽅法是⼀个⾮静态⽅法,在Java中要想调⽤它必须先实例化对象,然后再⽤对象调⽤它,那这个时候jobject就可以看做Java类的⼀个实例化对象,也就是obj就是t。

如果firstTest是⼀个静态⽅法,那么在Java中,它不是属于⼀个对象的,⽽是属于⼀个类的,Java中⽤Test.firstTest()这样的⽅式来调⽤,这个时候jobject就可以看做是java类的本⾝,也就是obj就是Test.class。

2、Jni中的数据类型
每⼀个Java的数据类型在Jni中都⼀个和它相对应的数据库类型,这样才能保证Java调⽤C或者C++的过程中数据的正确性。

打开Jni.h⽂件,有如下代码:
这⾥声明了所有Jni⽀持的数据类型,可以发现⼀个规律所有Jni的数据类型前⾯都有⼀个”J“字母,这样主要是为了好记。

在Java中所有的对象都以引⽤的形式体现的,为了保持⼀致所以在C与C++中使⽤了指针类型。

Java与Jni中数据类型的对照表如下:
3、实例:在C++.net程序中改变Java中变量的值
在原有Test.java中声明⼀个整形变量message,如下:
public class Test {
public native void firstTest();//第⼀个Jni
public int message;
public static void main(String[] args) {
System.loadLibrary("Jni01");
new Test().firstTest();
}
}
在Jni01的 Java_com_test01_Test_firstTest⽅法中写如下代码:
JNIEXPORT void JNICALL Java_com_test01_Test_firstTest(JNIEnv * env, jobject obj){
jclass class_Test=env->GetObjectClass(obj); //注释(1)
jfieldID fid_msg=env->GetFieldID(class_Test,"message","I");//注释(2)
env->SetIntField(obj,fid_msg,123);//注释(3)
}
(1)调⽤GetObjectClass⽅法来获取Jclass,GetObjectClass的参数就是obj
(2)调⽤GetFieldID⽅法来获取jfieldID,这⾥要说明⼀下Jni的所有操作,其实就是操作⽅法或者是操作属性两种。

操作⽅法时需要根据⽅法的ID(jmethodID)来操作,可以理解为jmethodID标识了这个⽅法,也就是通过这个jmethodID可以找到你要找的⽅法。

同理操作属性时也要根据该属性的ID(jfieldID )来操作。

上⾯那段代码⾥我们要改变变量message的值,所以要先获取该变量的jfieldID 。

获取变量的jfieldID ⽅法是GetFieldID。

GetFieldID需要3个参数。

第⼀个是上⼀步获取的Jclass,第⼆个参数是Java中的变量名,最后⼀个参数是变量签名(int 的变量签名是”I“)。

下⾯是所有Jni中的变量签名列表:
(3)最后调⽤SetIntField⽅法就可以设置变量 message的值了。

在JAVA的测试环境中打印⼀下变量的值就知道是否成功了。

全部完成后,可以⾃⼰试验下使⽤GetIntField⽅法将message的值取出来。

对于这些Jni.h中的⽅法就不过多的说了,⾃⼰看就应该能会⽤。

在以后的随笔⾥会多说⼀些数据转换的问题。

相关文档
最新文档