Chinaunix首页 | 论坛 | 博客
  • 博客访问: 687227
  • 博文数量: 112
  • 博客积分: 2486
  • 博客等级: 大尉
  • 技术积分: 1541
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-14 18:30
文章分类

全部博文(112)

文章存档

2012年(5)

2011年(48)

2010年(26)

2009年(33)

我的朋友

分类: LINUX

2011-09-01 22:47:58

本地代码访问Java代码
在被调用的C/C++函数中也可以反过来访问java程序中的类。

Java通过机制调用c/c++写的native程序。c/c++开发的native程序需要遵循一定的JNI规范,下面的例子就是一个JNI函数声明:

JNIEXPORT jint JNICALL Java_jnitest_MyTest_test
  (JNIEnv 
* env, jobject obj, jint arg0);
JVM负责从Java Stack转入C/C++ Native Stack。当Java进入JNI调用,除了函数本身的参数(arg0),会多出两个参数:JNIEnv指针和jobject指针。
JNIEnv指针是JVM创建的,用于Native的c/c++方法操纵Java执行栈中的数据,比如Java Class, Java Method等。

首先,JNI对于JNIEnv的使用, 提供了两种语法: c语法以及c++语法,如下:
c语法:
jsize len = (*env)->GetArrayLength(env,array);
c++语法:
jsize len =env->GetArrayLength(array);
(注:由于C语言并不支持对象的概念,所以C语法中需要把env作为第一个参数传入,类似于C++的隐式参数this指针).


另外: JNIEnv有几个设计的原则:
第一、JNIEnv指针被设计成了(TLS)变量,也就是说每一个Thread, JNIEnv变量都有独立的Copy。这样做的原因主要是考虑到:
由于JVM要运行在多个平台(除了主流的Windows,Linux等平台),JNI内部实现很 多要依赖到TLS, 为了减少对TLS的依赖,所有TLS based的数据都会存放于JNIEnv中。这样相当于只依赖一个TLS based的变量JNIEnv。由于JNIEnv指针是TLS的,所以你不能把Thead#1使用的JNIEnv传给Thread#2使用。

第 二、JNIEnv中定义了一组函数指针,c/c++ Native程序是通过这些函数指针操纵Java数据。这样设计的好处是:你的c/c++ 程序不需要依赖任何函数库,或者DLL。由于JVM可能由不同的厂商实现,不同厂商有自己不同的JNI实现,如果要求这些厂商暴露约定好的一些头文件和 库,这不是灵活的设计。
而 且使用函数指针表的另外一个好处是: JVM可以根据启动参数动态替换JNI实现。比如:类似于C库,JNI实现为了性能起见,并没有对调用者传入的参数进行检查。但是在调试阶段,也许这种检 查是很必要的,帮助你尽早发现BUG。例如如果你使用IBM JDK,你可以指定JVM参数–Xcheck:jni,告诉JVM使用带检查的JNI实现。
===================================================================

Javah工具生成的c/c++函数声明中,可以看到有两个参数。

JNIEnv类型
JNIEnv类型实际上代表了Java环境,通过这个JNIEnv*指针,可以对Java端的代码进行操作。例如,创建

Java类的对象,调用Java对象的方法,获取Java对象的属性等等。JNIEnv的指针会被JNI传入导本地方法

的实现函数中来对Java端的代码进行操作。

JNIEnv类中有很多函数可以用:
NewObject/NewString/NewArray
Get/SetField
Get/SetStaticField
CallMethod/CallStaticMethod等许许多多的函数

Java类型在C/C++中的映射关系
java类型  本地类型  JNI定义的别名
int       long      jint/jsize


jclass的取得
为了能够在C/C++中使用Java类。JNI.h头文件中专门定义了jclass类型来表示Java中的Class类。
JNIEnv类中有如下几个简单的函数可以取得jclass:
jclass FindClass(const char* clsName);
jclass GetObjectClass(jobject obj);
jclass GetSuperClass(jclass obj);

FindClass会在classpath系统环境变量下寻找类。传入完整类名,注意包与包之间是用‘/’而不是‘.’来分

隔。
jclass cls_string = env->FindClass("java/lang/String");

访问Java类中的属性与方法
在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

阅读(1204) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~