C调用java JNI_CreateJavaVM只能调用成功一次

程序小菜鸟 2017-09-17 07:09:12
再使用c语言调用java代码的时候,选择使用JNI,根据网上的提示已经能够正常跑了,
int mask_name( char* NAME, char * keyValue, char * weight )
{
/*
接下来,声明所有希望在程序中使用的变量。
JavaVMOption options[] 具有用于 JVM 的各种选项设置。
当声明变量时,确保所声明的JavaVMOption options[] 数组足够大,以便能容纳您希望使用的所有选项。
在本例中,我们使用的唯一选项就是类路径选项。
因为在本示例中,我们所有的文件都在同一目录中,所以将类路径设置成当前目录。
可以设置类路径,使它指向任何您希望使用的目录结构。*/
JavaVMOption options[4];
JNIEnv *env;
JavaVM *jvm;
JavaVMInitArgs vm_args;
/*JNIEnv *env 表示 JNI 执行环境。
JavaVM jvm 是指向 JVM 的指针,我们主要使用这个指针来创建、初始化和销毁 JVM。
JavaVMInitArgs vm_args 表示可以用来初始化 JVM 的各种 JVM 参数。*/

long status;
jclass cls;
jmethodID mid;
jstring square;


/*avaVMInitArgs 结构表示用于 JVM 的初始化参数。
在执行 Java 代码之前,可以使用这些参数来定制运行时环境。
正如您所见,这些选项是一个参数,而 Java 版本是另一个参数。
按如下所示设置了这些参数:*/

/*为 JVM 设置类路径,以使它能找到所需要的 Java 类。
在这个特定示例中,因为 Sample2.class 和Sample2.exe 都位于同一目录中,所以将类路径设置成当前目录。
我们用来为 Sample2.c 设置类路径的代码如下所示:*/
options[0].optionString = "-Djava.compiler=NONE";
options[1].optionString = "-Djava.class.path=C:\\algorithmfordm.jar";
options[2].optionString = "-Djava.library.path=C:\\Program Files\\Java\\jdk1.7.0_03\\jre\\bin\\server"; //指定加载的so路径
options[3].optionString = "-verbose:NONE"; //用于跟踪运行时的信息
//options[1].optionString = "-verbose.jni";
//options[0].optionString = "-Djava.class.path=.";
memset(&vm_args, 0, sizeof(vm_args));
vm_args.version=JNI_VERSION_1_6;//jdk版本1.6
vm_args.nOptions = 4;
vm_args.options = options;
vm_args.ignoreUnrecognized = JNI_TRUE;


/*创建 JVM
处理完所有设置之后,现在就准备创建 JVM 了。先从调用方法开始
如果成功,则这个方法返回零,否则,如果无法创建 JVM,则返回JNI_ERR。*/

status = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
printf("--------------------****%ld\n",status);
if (status != JNI_ERR)
{
/*
查找并装入 Java 类
一旦创建了 JVM 之后,就可以准备开始在本机应用程序中运行 Java 代码。
首先,需要使用FindClass() 函数查找并装入 Java 类,如下所示:
cls 变量存储执行FindClass() 函数后的结果,如果找到该类,则 cls 变量表示该Java 类的句柄,
如果不能找到该类,则 cls 将为零。
*/
cls = (*env)->FindClass(env, "com/wiseweb/algorithm/MobilePhoneFilterAlgorithm");
//(*env)->FindClass(env, "jni/JniTest");
printf("test1,cls=%d...\n",cls);

if(cls !=0)
{
/*
查找 Java 方法
接下来,我们希望用 GetStaticMethodID() 函数在该类中查找某个方法。
我们希望查找方法 intMethod,它接收一个 int 参数并返回一个 int。
以下是查找 intMethod 的代码:
*/
mid = (*env)->GetStaticMethodID(env, cls, "getModelMobilePhone", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
//mid = (*env)->GetStaticMethodID(env, cls, "getObjectMethod", "(Ljava/lang/Object;)Ljava/lang/Object;");

/*
mid 变量存储执行 GetStaticMethodID() 函数后的结果。
如果找到了该方法,则 mid 变量表示该方法的句柄。
如果不能找到该方法,则mid 将为零。
*/
if(mid !=0)
{
/*CallStaticIntMethod() 方法接受 cls(表示类)、mid(表示方法)以及用于该方法一个或多个参数。
在本例中参数是 int 5。*/
//char * p = "422202199109300010";
char showTime[20];
char * t = getTime(showTime);
jstring value = (*env) ->NewStringUTF(env , NAME);
//char *str = (char *)(*env)->GetStringUTFChars(env,value,0);
//printf("%s\n",str);
jstring keyvalue = (*env) ->NewStringUTF(env , keyValue);
jstring timevalue1 = (*env) ->NewStringUTF(env , t);
jstring quanzhi = (*env) ->NewStringUTF(env , weight);
square = (jstring)(*env)->CallStaticObjectMethod(env, cls, mid,value,keyvalue,timevalue1,quanzhi);
//square = (*env)->CallStaticIntMethod(env, cls, mid,4);
char *str1 = (char *)(*env)->GetStringUTFChars(env,square,0);
//printf("%s\n",str1);
memset(NAME,0X00,11);
if(strcmp(NAME, str1) != 0){
int i ;
for(i = 0; i < strlen(str1); i++){
NAME[i] = str1[i];
}
}
}
}
if ((*env)->ExceptionOccurred(env)) {

(*env)->ExceptionDescribe(env);

}
jint end = (*jvm)->DestroyJavaVM(jvm);
printf("-------------00000000000--%d\n",end);
return 0;

}
else
{
return -1;

}




}


int main()
{
int k ;
for(k = 0; k < 3; k++){
char NAME[] = {"15007113427"};
char keyValue[] = {"457685645971234574"};
char weight[] = {"40"};
mask_name(NAME,keyValue,weight);
//printf("Hello world!%d\n",sizeof(NAME));
printf("-----------------------11111111111--------%s\n",NAME);

}
system ("pause");
return 0;
}
...全文
995 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
程序小菜鸟 2018-03-30
  • 打赏
  • 举报
回复
在执行c调用java的过程中只要执行一次JNI_CreateJavaVM,结束之后在执行DestroyJavaVM,不要把JNI_CreateJavaVM执行多次
哈哈aa 2018-03-02
  • 打赏
  • 举报
回复
你好,关于用jni调用java虚拟机,JNI_CreateJavaVM后,DestroyJavaVM,然后在JNI_CreateJavaVM出错了,返回-1,这个要怎么解决,还望指点一二,谢谢
程序小菜鸟 2017-09-21
  • 打赏
  • 举报
回复
因为代码开发的是dll文件 ,不能单独初始化, 我选择将java虚拟机做成静态,但是注销虚拟机这个操作就没法进行了。感谢大家的帮助,这个贴我结了!
Dobzhansky 2017-09-20
  • 打赏
  • 举报
回复
jvm 在进程内就是只能初始化一次的, 你把jvm寄宿从功能调用中分离出来单独初始化
  • 打赏
  • 举报
回复
直接通过命令行调用更简单: java -jar xxx.jar param1 param2... >out.txt 其中param1等是传入的命令行参数,数据可以作为参数传入,或者作为文件名传入。 然后通过读取out.txt获取它的运行结果。
赵4老师 2017-09-20
  • 打赏
  • 举报
回复
c语言通过读写临时文本文件,间接调用java写的读写相同临时文本文件并调用jar包的程序。
程序小菜鸟 2017-09-19
  • 打赏
  • 举报
回复
您好 , 跨语言并非我所愿,只是因为需求是这样的,本来运行IBM的optim的脱敏函数接口是用C语言开发的。但是客户需要我们用他们的算法,而且不给算法我们,只给我一个jar包让我们调用,现在大部分难点都慢慢解决了 ,但是卡在c语言重复调用jar包的问题上了,希望赵老师能给我提供一点思路
赵4老师 2017-09-18
  • 打赏
  • 举报
回复
不要做A语言代码修改为B语言代码的无用功。 也不要做用A语言代码直接调用B语言代码库这样复杂、这样容易出错的傻事。 只需让A、B语言代码的输入输出重定向到文本文件,或修改A、B语言代码让其通过文本文件输入输出。 即可很方便地让A、B两种语言之间协调工作。 比如: A将请求数据写到文件a.txt,写完后改名为aa.txt B发现aa.txt存在时,读取其内容,调用相应功能,将结果写到文件b.txt,写完后删除aa.txt,再将b.txt改名为bb.txt A发现bb.txt存在时,读取其内容,读完后删除bb.txt 以上A可以替换为任何一种开发语言或开发环境,B可以替换为任何一种与A不同的开发语言或开发环境。 除非A或B不支持判断文件是否存在、文件读写和文件更名。 但是谁又能举出不支持判断文件是否存在、文件读写和文件更名的开发语言或开发环境呢? 可以将临时文件放在RamDisk上提高效率减少磨损磁盘。 数据的结构很复杂的话,文本文件的格式问题可参考json或xml 共享临时文本文件这种进程之间的通讯方法相比其它方法的优点有很多,下面仅列出我现在能想到的: ·进程之间松耦合 ·进程可在同一台机器上,也可跨机,跨操作系统,跨硬件平台,甚至跨国。 ·方便调试和监视,只需让第三方或人工查看该临时文本文件即可。 ·方便在线开关服务,只需删除或创建该临时文本文件即可。 ·方便实现分布式和负载均衡。 ·方便队列化提供服务,而且几乎不可能发生队列满的情况(除非硬盘空间满) ·…… “跨语言、跨机,跨操作系统,跨硬件平台,跨国,跨*.*的”苦海无边, 回头是“使用共享纯文本文件进行信息交流”的岸!
目录 I. 目录 1 II. java c/cpp互相调用实例(姊妹篇之一)——java调用c/cpp 4 一 先制作一个系统中有的DLL文件(cpp给出的sdk接口) 4 二 JNI 7 1、 编写java文件 7 2、 生成.h头文件 8 3、 用c/cpp实现这个头文件 9 三 测试 10 四 最后补充 11 III. java c/cpp互相调用实例(姊妹篇之二)——c/cpp调用java 11 一、 编写java代码 12 二、 编译java代码 12 三、 编写 C/C++ 代码 13 四、 运行exe 18 IV. Java JNI 编程进阶 18 一、 解决性能问题 18 二、 解决本机平台接口调用问题 19 三、 嵌入式开发应用(JNI小例子) 20 1、 新增一个基础类 22 2、 定义新类继承基础类 23 3、 编写调用类 23 4、 新增两个本地方法 24 5、 修改 RunMain 类 25 6、 新增一个方法处理java对象 26 7、 新增一个方法处理数组 29 8、 改写RunMain 32 四、 参考资料: 33 V. Eclipse+CDT+MinGW 进行JAVA调用C/C++ 34 一、 安装eclipse3.2。 34 二、 安装MinGW。 34 1、 下载MinGW 34 2、 安装 34 3、 安装版本 34 4、 选择安装的编译器 34 5、 选择安装路径,下一步 35 6、 等待下载软件 35 三、 MinGW的环境变量设置 35 1、 设置Path 35 2、 设置C_INCLUDE_PATH 35 3、 设置CPLUS_INCLUDE_PATH 35 四、 做一个小技巧修改 35 五、 安装CDT插件 36 1、 下载CDT插件 36 2、 安装CDT插件 36 六、 简单介绍CDT的使用吧 36 1、 新建一个C++项目 36 2、 输入New Project名字 36 3、 给项目新建一个的源文件 36 4、 接着出现文件添加的窗口,在File Name栏里面写上文件名 36 5、 编辑hello.cpp 37 6、 添加一个编译命令 37 七、 让我们开始进入真正的工作吧! 38 The Java side 38 1、 建立Java工程JavaHello,编写java类 38 2、 用命令生成头文件 38 The C side-Compiling the Library 40 1、 建立标准C工程Cpro,并生成dll文件 40 1) 将生成的头文件test_Hello.h拷贝到C工程Cpro下 40 2) 编写C类Hello.c,内容为: 40 3) 在C工程Cpro下建立hello.def文件(用于定义导出的函数),内容为: 40 4) 在C工程Cpro下建立makefile文件,内容为: 40 5) Make Targets 40 6) Make Targets视图下双击step1,在C工程Cpro下生成hello.o 文件。 41 7) Make Targets视图下双击step1,在C工程Cpro下生成hello.dll 文件。 41 2、 JAVA调用DLL 41 1) 将hello.dll拷贝到Java工程JavaHello下。 41 2) 运行Hello.java,则可以看到输出结果: 41 1) 将Hello.c改为Hello.cpp 41 2) 将makefile内容改为: 41 3) 其他的几乎都不用改变也可以。 42 评论: 42 VI. c++如何调用java程序 51 DemoMain.java内容如: 51 采用vc6++ IDE,采用JNI技术实现。 51 1、 编译时 51 2、 运行时 51 程序的关键在 53 VII. JNI 53 一、 定义 53 二、 设计目的 54 三、 书写步骤 54 1) 编写java程序:这里以HelloWorld为例。 54 2) 编译 55 3) 生成扩展名为h的头文件 55 4) 编写本地方法实现和由javah命令生成的头文件里面声明的方法名相同的方法。 56 5) 生成动态库 56 6) 运行程序 java HelloWorld就ok. 56 四、 调用中考虑的问题 56 1) java和c是如何互通的? 57 2) 如何将java传入的String参数转换为c的char*,然后使用? 57 3) 将c中获取的一个char*的buffer传递给java? 57 4) 不知道占用多少空间的buffer,如何传递出去呢? 58 五、 对JAVA传入数据的处理 58 1) 如果传入的是bytearray的话,作如下处理得到buffer: 58 VIII. C/C++调用JAVA类 58 一、 加载虚拟机: 59 二、 获取指定对象的类定义: 59 三、 获取要调用的方法: 59 四、 调用JAVA类方法: 60 五、 获得类属性的定义: 60 六、 数组处理: 60 七、 异常: 60 八、 多线程调用 61 Java代码 61 命令行运行:javap -s -p MyTest ,输出: 62 C代码testjava.c: 62 编译: 65 运行结果: 65

70,039

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧