JNI

 

  1. 用本地方法創建Java源代碼
      native return type method (arguments);
 
  1. 編譯Java源代碼,獲得class文件
  2. 爲本地方法生成C/C++頭文件;javah從class文件中獲得它需要的信息
  3. 使用生成的包含文件的函數原型和include/jni.h中的類型定義寫出本地方法的C/C++源代碼
  4. 和頭文件一起編譯C/C++文件
  5. 用鏈接器創建動態庫
  6. 運行Java程序裝載動態庫
      static {
         System.loadLibrary("dynamic libary");
      }
例子
HelloWorld
1.創建Java源代碼,就是說,把本地方法放在HelloWorld.java裏面。需要裝載動態庫。
2.編譯Java源代碼,獲得class文件。

         javac HelloWorld.java

3. 爲本地方法生成C/C++頭文件
javah -jni HelloWorld
4. 使用生成的包含文件裏面的函數原型和jni.h裏面的類型定義來編寫本地方法的C/C++ 源代碼,也就是, HelloWorld.c
5.和頭文件一起編譯C/C++文件,生成*.o文件。
gcc -I/software/java/jdk1.2.2/include -I/software/java/jdk1.2.2/include/solaris -c HelloWorld.c -o HelloWorld.o
6. 用鏈接器創建動態庫文件

         ld -G HelloWorld.o -o libHelloWorld.so

7.運行裝載動態庫的Java程序

       java -Djava.library.path=. HelloWorld

       Hello World!

    (在Unix上可以用setenv LD_LIBRARY_PATH .來代替)當前目錄”.”作爲Java裝載庫的缺省路徑。
 
C/C++
C

 JNIEXPORT void JNICALL

 Java_ ... (JNIENV *env, ...) {

    (*env)->GetFieldID (env, ...);

 }

C++

 JNIEXPORT void JNICALL

 Java_ ... (JNIENV *env, ...) {

    env->GetFieldID (...);

 }

設置域值(fields)
獲取域值(fields)

 jclass c = (*env)->GetObjectClass(env, this);

 jfieldID fid = (*env)->GetFieldID(env, c, "private_variable", "I");

 (*env)->SetIntField (env, this, fid, val);

  jclass c = (*env)->GetObjectClass(env, this);

 jfieldID fid = (*env)->GetFieldID(env, c, "private_variable", "I");

 jint val = (*env)->GetIntField(env, this, fid);

訪問其他類(classes)

 jclass c = (*env)->GetObjectClass(env, this);

 JNIEXPORT void JNICALL

 Java_AccessOther_setPrivate (JNIENV *env, jobject this, jobject other, jint val) {

    jclass c = (*env)->GetObjectClass(env, other);

 }

類型(types)
 

例子

JNI調用Java方法
構建方法描述符

 private String getLine (String)            (Ljava/lang/String;)Ljava/lang/String;

 public static void main (String [] args)   ([Ljava/lang/String;)V

 getMethodID (JNIEnv, jclass, char* name, char* descriptor)
 
有三種形式來調用Java方法:
1.實例方法
2.類方法
3.在超類中重載的實例方法
  JNI type CalltypeMethod (jobject, jmethodID, arguments);

 JNI type CallStatictypeMethod (jobject, jmethodID, arguments);

 JNI type CallNonvirtualtypeMethod (jobject, jmethodID, arguments);

構造函數名爲<inti>
 
有三種形式來傳遞變數參數:
1.有不同數量參數的JNI子進程
2.Jvalue*(數組)類型的參數
3.Va_list類型的參數
 
 JNItypeCalltypeMethod (jobject obj, jmethodID mid, ...);

 JNItypeCalltypeMethodA (jobject obj, jmethodID mid, jvalue* args);

 JNItypeCalltypeMethodV (jobject obj, jmethodID mid, va_list args);

 
數組(arrays)

 NewObjectArray

 GetArrayLength

 SetObjectElement

字符串(strings)
Java字符串內部用UTF-8存儲。不能在C/C++中直接使用。

 JNIEXPORT jstring JNICALL

 Java_Strings_printString (JNIEnv *env, jclass this, jstring str) {

     const char* utf_string;

     jboolean    is_copy;

     utf_string = env->GetStringUTFChars (str, &isCopy);

     printf ("%s\n", utf_string);

     if (isCopy == JNI_TRUE) {

        env->ReleaseStringUTFChars (str, utf_string);

     }

 }

這樣在本地代碼中創建Java字符串:

 JNIEXPORT jstring JNICALL

 Java_NewString_newStringUTF (JNIEnv *env, jclass this) {

     const char* msg = "String constructed using NewStringUTF";

     return env->NewStringUTF(msg);

 }

 
異常(exceptions)

 jclass cls = (*env)->FindClass (env, "java/lang/IllegalArgumentException");

 if (cls==NULL) return; // Give up

 (*env)->ThrowNew (env, cls, "message");

 return;

 (*env)->CalltypeMethod (env, obj, method_id)

 jthrowable exc = (*env)->ExceptionOccurred(env)

 if (exc) {

    (*env)->ExceptionClear(env)

 }

調用JVM

 int main (int argc, char *argv[]) {

    JNIEnv *env;

    JavaVM *jvm;

    int i;

    JDK1_1InitArgs vm_args;     // env variables to control invocation

     jint ret;

    jmethodID mid;

    vm_args.version = 0x00010001;

    JNI_GetDefaultJavaVMInitArgs(&vm_args);

    int len = strlen(MY_CLASSPATH) + strlen(vm_args.classpath) + 1;

    char * newcp = (char*) malloc(len * sizeof(char));

    strcpy(newcp, MY_CLASSPATH);

    strcat(newcp, vm_args.classpath);

    vm_args.classpath = newcp;

    vm_args.properties = properties;

    vm_args.vfprintf = y_fprintf;

    vm_args.exit = y_exit;

    vm_args.abort = y_abort;

     ret = JNI_CreateJavaVM(&jvm,&env,&vm_args);

    if (ret < 0) {

        fprintf(stderr, "Can't create Java VM. Error: %ld\n", ret);

        return(1);

    }

    if (argc < 2) {

        printf("No class specified. Exiting...\n\n");

        return(-1);

    }

    jstring jstr = env->NewStringUTF("");

    jobjectArray str_array =

         env->NewObjectArray(argc-2, env->FindClass("java/lang/String"), jstr);

    // Pass main arguments to Java

    for( i = 2; i < argc; i++ ) {

         jstr = env->NewStringUTF (argv[i]);

         if (jstr == 0) {

                fprintf(stderr, "Out of memory\n");

                return(1);

         }

         env->SetObjectArrayElement( str_array, i - 2, jstr);

    }

    jclass clazz = env->FindClass(dotsToSlashes(argv[1]));

    if (clazz == 0) {

       fprintf(stderr, "Can't locate the %s class. Exiting...\n", argv[1]);

       return(1);

    }

    mid = env->GetStaticMethodID(clazz, "main", "([Ljava/lang/String;)V");

    if (mid == 0) {

        fprintf(stderr, "Can't locate the main method. Exiting...\n");

        return(1);

    }

    env->CallStaticVoidMethod (clazz, mid, str_array);

    jvm->DestroyJavaVM();

    return(0);

 }

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章