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
HelloWorld.h包含Java系统安装目录下的include/jni.h。 jni.h 包含了C/C++函数原型以及系统依赖文件jni_md.h。
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 Call typeMethod (jobject, jmethodID, arguments);

 JNI type CallStatictypeMethod (jobject, jmethodID, arguments);

 JNI type CallNonvirtualtypeMethod (jobject, jmethodID, arguments);

构造函数名为 <inti> 。
 
有三种形式来传递变数参数:
1. 有不同数量参数的 JNI子进程
2. Jvalue* (数组)类型的参数
3. Va_list 类型的参数
 
  JNItypeCall typeMethod (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);

 }

 

 

你可能感兴趣的:(java,C++,c,jni,休闲)