JNI编程入门(-)

来源:互联网 发布:杨辉三角c语言程序 编辑:程序博客网 时间:2024/05/10 13:28

最新因工作需要,需要在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

  1.   //定义一个函数指针,下面用来指向JVM中的JNI_CreateJavaVM函数  
  2.     typedef jint (WINAPI *PFunCreateJavaVM)(JavaVM **, void **, void *);  
  3.       
  4.     int res;  
  5.     JavaVMInitArgs vm_args;  
  6.     JavaVMOption options[3];  
  7.     JavaVM *jvm;  
  8.     JNIEnv *env;  
  9.       
  10.     /*设置初始化参数*/  
  11.     //disable JIT,这是JNI文档中的解释,具体意义不是很清楚 ,能取哪些值也不清楚。  
  12.     //从JNI文档里给的示例代码中搬过来的  
  13.     options[0].optionString = "-Djava.compiler=NONE";  
  14.     //设置classpath,如果程序用到了第三方的JAR包,也可以在这里面包含进来  
  15.     options[1].optionString = "-Djava.class.path=.;c:\\";  
  16.     //设置显示消息的类型,取值有gc、class和jni,如果一次取多个的话值之间用逗号格开,如-verbose:gc,class  
  17.     //该参数可以用来观察C++调用JAVA的过程,设置该参数后,程序会在标准输出设备上打印调用的相关信息  
  18.     options[2].optionString = "-verbose:NONE";  
  19.           
  20.     //设置版本号,版本号有JNI_VERSION_1_1,JNI_VERSION_1_2和JNI_VERSION_1_4  
  21.     //选择一个根你安装的JRE版本最近的版本号即可,不过你的JRE版本一定要等于或者高于指定的版本号  
  22.     vm_args.version = JNI_VERSION_1_4;  
  23.     vm_args.nOptions = 3;  
  24.     vm_args.options = options;  
  25.     //该参数指定是否忽略非标准的参数,如果填JNI_FLASE,当遇到非标准参数时,JNI_CreateJavaVM会返回JNI_ERR  
  26.     vm_args.ignoreUnrecognized = JNI_TRUE;  
  27.     //加载JVM.DLL动态库  
  28.     HINSTANCE hInstance = ::LoadLibrary("C:\\j2sdk1.4.2_15\\jre\\bin\\client\\jvm.dll");  
  29.     if (hInstance == NULL)  
  30.     {  
  31.         return false;  
  32.     } 














0 0