最新因工作需要,需要在C++的开发中使用到Java,所以就想到了利用JNI来进行开发,JNI全称Java Native Interface,也就是Java的本地接口,JNI既可以实现Java到本地平台的开发,也可以将本地平台的开发移植到Java上(当然,这里必须要保证二进制的位数一样,因为Java也是程序,JVM也是区分32位版本和64位版本的),下面就简单介绍一下JNI的双向操作,本文章以Java <----> C++的开发为例:
1.在Java中开发,使用C++的库
<1>在Java程序中使用C++,需要在类中声明C++的导出函数。
<2>将相应的动态库加载到Java程序中。
<3>将Java程序中的JNI函数使用javah来生成C/C++的头文件
public class Demo{
public static native int getSum(int x, int y);
public static native int getSub(int x, int y);
public static void main(String[] args){
System.loadLibrary("xxx");
//******这里需要注意的是不需要写动态库后缀
//******windows上默认是.dll,Linux上默认是.so
}
}
下面重点介绍JNI在C++中的开发
2.在C++中开发,使用Java的jar包
在C++中开发使用jar包,首先要确定咱们的C++程序是32位还是64位,因为这个决定了我们的程序应该使用32位
还是64位的jre(java runtime environment),java的运行程序jar包(其实也就是*.class是不区分32位和64位的),
<1>建立Java的虚拟机JVM
<2>将jar包作为JVM运行时的类,启动JVM的时候作为启动参数加入
<3>使用JVM的虚拟环境来查找类、查找类函数、查找域,调用函数,根据构造函数创建类对象
C++中在JVM中使用的几种环境
(1)创建一个类对象
jclass cls = env->FindClass("test/Demo");
jmethodID mid = env->GetMethodID(cls,"<init>","(Ljava/lang/String;)V");
const char szTest[] = "电信";
jstring arg = NewJString(env, szTest);
jobject demo = env->NewObject(cls,mid,arg);
(2)查找一个类
jclass cls = env->FindClass("test/Demo");
这里写类的路径的时候,将完整的类拷贝过来
然后将.改成/即可。例如com.example的类则写成
com/example
(3)查找方法ID
env->GetMethodID(cls,"<init>","(Ljava/lang/String;)V");
特别要注意的是由于这里是构造函数所以使用的是
<init>,其他的类函数则使用相应的函数名称,
特别要注意的是函数的签名,千万最好是从jar包中查看
或者通过javap -s 解析*.class来查看签名,如果手写有时候
容易写错
(4)调用方法
env->CallObjectMethod(demo, mid);
调用的函数根据返回值类型不同而不同
Call###Method,其中###是基本类型或Object
由于String从Object派生,所以String也调用该函数
(5)查找域ID
env->GetStaticFieldID(classID,fieldname,sig)
env->GetBoolFieldID
env->GetObjectFieldID
env->Get###FieldID
这里特别需要注意的有两点
1>如果是静态变量则第一个参数传入类指针,否则传入对象指针
2>除了基础类型以外,其他的均为GetObjectFieldID
(6)获取域值
env->GetStaticObjectField(classPtr, fieldID)
env->GetBooleanField(objectPtr, fieldID)
env->GetObjectField(objectPtr, fieldID);
规则与查找域的前两条一致
(7)调用带参数的构造函数
jclass cls = env->FindClass("test/Demo");
jmethodID mid = env->GetMethodID(cls,"<init>","(Ljava/lang/String;)V");
const char szTest[] = "电信";
jstring arg = NewJString(env, szTest);
jobject demo = env->NewObject(cls,mid,arg);
//验证是否构造成功
mid = env->GetMethodID(cls, "getMessage","()Ljava/lang/String;");
jstring msg = (jstring)env->CallObjectMethod(demo, mid);
cout<<JStringToCString(env, msg);
详情查阅官方文档
http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/functions.html#wp4517
创建JVM的Demo
- //定义一个函数指针,下面用来指向JVM中的JNI_CreateJavaVM函数
- typedef jint (WINAPI *PFunCreateJavaVM)(JavaVM **, void **, void *);
- int res;
- JavaVMInitArgs vm_args;
- JavaVMOption options[3];
- JavaVM *jvm;
- JNIEnv *env;
- /*设置初始化参数*/
- //disable JIT,这是JNI文档中的解释,具体意义不是很清楚 ,能取哪些值也不清楚。
- //从JNI文档里给的示例代码中搬过来的
- options[0].optionString = "-Djava.compiler=NONE";
- //设置classpath,如果程序用到了第三方的JAR包,也可以在这里面包含进来
- options[1].optionString = "-Djava.class.path=.;c:\\";
- //设置显示消息的类型,取值有gc、class和jni,如果一次取多个的话值之间用逗号格开,如-verbose:gc,class
- //该参数可以用来观察C++调用JAVA的过程,设置该参数后,程序会在标准输出设备上打印调用的相关信息
- options[2].optionString = "-verbose:NONE";
- //设置版本号,版本号有JNI_VERSION_1_1,JNI_VERSION_1_2和JNI_VERSION_1_4
- //选择一个根你安装的JRE版本最近的版本号即可,不过你的JRE版本一定要等于或者高于指定的版本号
- vm_args.version = JNI_VERSION_1_4;
- vm_args.nOptions = 3;
- vm_args.options = options;
- //该参数指定是否忽略非标准的参数,如果填JNI_FLASE,当遇到非标准参数时,JNI_CreateJavaVM会返回JNI_ERR
- vm_args.ignoreUnrecognized = JNI_TRUE;
- //加载JVM.DLL动态库
- HINSTANCE hInstance = ::LoadLibrary("C:\\j2sdk1.4.2_15\\jre\\bin\\client\\jvm.dll");
- if (hInstance == NULL)
- {
- return false;
- }