Monday, November 17, 2008

JNI接口简介

        本文简单介绍一下JNI接口,更多细节可以参考JNI规范。JNI接口是Java Native API的缩写,它是Java语言和C语言之间的接口。在上一篇里,我们已经看到怎么利用JNI接口开始运行Java程序的。本篇将讲述Java程序里面怎么调用C的代码。
        先以一个简单的例子开始。还是程序员熟悉的Hello World程序,只是我们要求显示一个消息框而不是控制台里的文字。这通过在本地方法里调用MessageBox来实现。先看Java代码:
          class Hello {
             public static native void sayHello(String name);        
                     // 我们要在C语言中实现的本地方法

             static {
                System.loadLibrary("hello");
                     // 载入hello.dll库
             }

             public static void main(String[] argv) {
                sayHello("Tommy");
             }
          }
运行命令java Hello.java生成class文件,再调用javah Hello生产头文件。(对,javah中的‘h’就是header的意思!)这个头文件包括了sayHello的C语言实现的原型。为了简单起见,我们直接修改生产的头文件为:
          #include
          #include

          #ifdef __cplusplus
          extern "C" {
          #endif

          /*
            * Class:     Hello
            * Method:    sayHello
            * Signature: (Ljava/lang/String;)V
            */
          JNIEXPORT void JNICALL Java_Hello_sayHello(JNIEnv* jni_env,
                                                                                                    jclass cls,
                                                                                                    jstring name) {
              const jchar* unicode_name = (*jni_env)->GetStringChars(
                      jni_env, name, NULL);
                        // name是Java的String对象,我们需要将其
                        // 转换为wchar_t的指针。
              wchar_t message[20];
              swprintf(message, 20, L"Hello %s", unicode_name);
              (*jni_env)->ReleaseStringChars(name, unicode_name);
              MessageBoxW(NULL, message, L"JNI_TEST", MB_OK);
          }

          #ifdef __cplusplus
          }
          #endif
编译:cl /c /I..\src\share\javavm\export Hello.c
            link /dll Hello.obj user32.lib jvm.lib。
        从这个简单例子里可以看出,和上一篇创建Java虚拟机并运行Java程序的方法是一样的,即调用JNI函数完成我们需要的功能;不同的是在Java本地方法里我们直接获得了JNI的指针,不需要通过创建虚拟机获得它。下文将描述一下JNI提供的主要方法,从这里我们可以看到Java虚拟机的一个大致功能框架。
        JNI提供了下述这些功能:
  1. Java类相关函数,包括DefineClass和FindClass
  2. 异常相关函数,包括Throw,ThrowNew以及检查异常状态的ExceptionOccurred,ExceptionDescribe和ExceptionClear
  3. 对象相关函数,包括AllocObject,NewGlobalRef,NewLocalRef,DeleteLocalRef
  4. 访问对象成员、方法的函数,包括GetFieldID,GetField,SetField,GetMethodID,CallMethod和CallNonvirtualMethod(代表成员类型或者方法返回值)
  5. 访问类的成员、方法的函数(即静态成员和方法,和上面类似,只是在Get/Set后加上了Static)字符串相关函数,包括NewString,GetStringLength,GetStringChars,ReleaseStringChars(这一组是操作Unicode字符串的,还有一组是操作UTF8的,在String后面加上UTF)
  6. 数组相关函数,包括GetArrayLength,NewObjectArray,GetObjectArrayElement,SetObjectArrayElement(这一组是操作对象数组的,对于每个原始类型都有这样的一套函数)
这些函数的用途可以从名字上看出,具体信息请参考这里
              

No comments: