使用JNI进行Java与C/C++语言混合编程(2)

时间:2017-11-01 16:37

JNI系列文章索引

使用JNI进行Java与C/C++语言混合编程(1)--在Java中调用C/C++本地库

使用JNI进行Java与C/C++语言混合编程(2)--在C/C++中调用Java代码

JNI就是Java Native Interface, 即可以实现Java调用本地库, 也可以实现C/C++调用Java代码, 从而实现了两种语言的互通, 可以让我们更加灵活的使用.

通过使用JNI可以从一个侧面了解Java内部的一些实现.

本文使用的环境是

64位的win7系统

JDK 1.6.0u30 (32位)

C/C++编译器是 Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8168 for 80x86 (VC 6.0的, 其他版本的也可以编译通过, 测试过vs2010)

本文使用到的一些功能:

创建虚拟机

寻找class对象, 创建对象

调用静态方法和成员方法

获取成员属性, 修改成员属性

C/C++调用Java代码的一般步骤:

编写Java代码, 并编译

编写C/C++代码

配置lib进行编译, 配置PATH添加相应的dll或so并运行

编写Java代码并编译

这段代码非常简单, 有个静态方法和成员方法, 一个public的成员变量

public class Sample2 { public String name; public static String sayHello(String name) { return "Hello, " + name + "!"; } public String sayHello() { return "Hello, " + name + "!"; } }

由于没有定义构造函数, 所以会有一个默认的构造函数.

运行下面的命令编译

>javac Sample2.java

可以在当前目录下看到Sample2.class文件, 编译成功, 第一步完成了, So easy!

可以查看Sample2类中的签名

>javap -s -private Sample2

结果如下

Compiled from "Sample2.java" public class Sample2 extends java.lang.Object{ public java.lang.String name; Signature: Ljava/lang/String; public Sample2(); Signature: ()V public static java.lang.String sayHello(java.lang.String); Signature: (Ljava/lang/String;)Ljava/lang/String; public java.lang.String sayHello(); Signature: ()Ljava/lang/String; }

关于签名的含义, 请参看使用JNI进行Java与C/C++语言混合编程(1)--在Java中调用C/C++本地库.

编写C/C++代码调用Java代码

先贴代码吧

#include <jni.h> #include <string.h> #include <stdio.h> // 环境变量PATH在windows下和linux下的分割符定义 #ifdef _WIN32 #define PATH_SEPARATOR ';' #else #define PATH_SEPARATOR ':' #endif int main(void) { JavaVMOption options[1]; JNIEnv *env; JavaVM *jvm; JavaVMInitArgs vm_args; long status; jclass cls; jmethodID mid; jfieldID fid; jobject obj; options[0].optionString = "-Djava.class.path=."; memset(&vm_args, 0, sizeof(vm_args)); vm_args.version = JNI_VERSION_1_4; vm_args.nOptions = 1; vm_args.options = options; // 启动虚拟机 status = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args); if (status != JNI_ERR) { // 先获得class对象 cls = (*env)->FindClass(env, "Sample2"); if (cls != 0) { // 获取方法ID, 通过方法名和签名, 调用静态方法 mid = (*env)->GetStaticMethodID(env, cls, "sayHello", "(Ljava/lang/String;)Ljava/lang/String;"); if (mid != 0) { const char* name = "World"; jstring arg = (*env)->NewStringUTF(env, name); jstring result = (jstring)(*env)->CallStaticObjectMethod(env, cls, mid, arg); const char* str = (*env)->GetStringUTFChars(env, result, 0); printf("Result of sayHello: %s\n", str); (*env)->ReleaseStringUTFChars(env, result, 0); } /*** 新建一个对象 ***/ // 调用默认构造函数 //obj = (*env)->AllocObjdect(env, cls); // 调用指定的构造函数, 构造函数的名字叫做<init> mid = (*env)->GetMethodID(env, cls, "<init>", "()V"); obj = (*env)->NewObject(env, cls, mid); if (obj == 0) { printf("Create object failed!\n"); } /*** 新建一个对象 ***/ // 获取属性ID, 通过属性名和签名 fid = (*env)->GetFieldID(env, cls, "name", "Ljava/lang/String;"); if (fid != 0) { const char* name = "icejoywoo"; jstring arg = (*env)->NewStringUTF(env, name); (*env)->SetObjectField(env, obj, fid, arg); // 修改属性 } // 调用成员方法 mid = (*env)->GetMethodID(env, cls, "sayHello", "()Ljava/lang/String;"); if (mid != 0) { jstring result = (jstring)(*env)->CallObjectMethod(env, obj, mid); const char* str = (*env)->GetStringUTFChars(env, result, 0); printf("Result of sayHello: %s\n", str); (*env)->ReleaseStringUTFChars(env, result, 0); } } (*jvm)->DestroyJavaVM(jvm); return 0; } else { printf("JVM Created failed!\n"); return -1; } }

这段代码大概做了这几件事

创建虚拟机JVM, 在程序结束的时候销毁虚拟机JVM

寻找class对象

创建class对象的实例

调用方法和修改属性

虚拟的创建

与之相关的有这样几个变量

JavaVMOption options[1];
    JNIEnv *env;
    JavaVM *jvm;
    JavaVMInitArgs vm_args;

JavaVM就是我们需要创建的虚拟机实例

JavaVMOption相当于在命令行里传入的参数

JNIEnv在Java调用C/C++中每个方法都会有的一个参数, 拥有一个JNI的环境

JavaVMInitArgs就是虚拟机创建的初始化参数, 这个参数里面会包含JavaVMOption

下面就是创建虚拟机

  • A+
所属分类:C/C++