c/cpp调用java方法 实例

java c/cpp互相调用实例(姊妹篇之二)
                             ----------c/cpp调用java

本文是 javaJNI调用c/cpp实例(姊妹篇之一)的续集c/cpp调用java。

计划第三篇写一个java安装程序实例(客户端无jre环境的安装包),以解决java程序(软件)安装不方便的问题,使java程序安装也傻瓜化。

直接进入正题:

完成本实例需要下列工具/环境:
1、java环境
2、c/cpp编辑器。windows下推荐用vs/vc++,我用的是vs2008。linux下gcc/g++

从 C/CPP 程序调用 Java 代码需要四个步骤 :
一 编写 Java 代码。
二 编译 Java 代码。
三 编写 C/C++ 代码。
四 运行本机 C/C++ 应用程序。

1、编写java代码

为了达到示范作用,java方法我用两个,一个是静态方法,一个是普通方法。

C2java.java
package com.testJni.testDemo;

public class C2java {
	public C2java(){
		super();
	}
	public static int add(int a,int b) {
		return a+b;
	}
	public boolean judge(boolean bool) {
		return !bool;
	}

}


静态方法的好处是我不用实例化,直接可以调用方法。调用起来比较简单,不容易出错。

2、编译java代码

javac 命令。(略)

3、编写 C/C++ 代码

我想在c/cpp中直接生成一个exe然后窗口输出结果,所以我就建立一个exe工程。编辑器jni环境是上篇已经搭建好的,所以这里只需要少量配置就可以了。好了,我们先建立一个工程:

打开vs2008,新建一 win32 console App 工程
c/cpp调用java方法 实例_第1张图片
键入工程名字c2java,点击OK,出来窗口点击next,选取console app
c/cpp调用java方法 实例_第2张图片
点击完成。到这里先不忙编码实现,我们先把环境搭建好,右键工程属性,选取 linker -->input,在右边窗口添加依赖jvm.lib,这个lib的位置在你%JAVA_HOME%/lib 下。如果你的路径中同我一样包含空格(例如Program Files)记得用引号括起来。
c/cpp调用java方法 实例_第3张图片
打开stdafx.h文件添加
#include <iostream>
#include <jni.h>

#ifdef _WIN32
#define PATH_SEPARATOR ';'
#else
#define PATH_SEPARATOR ':'
#endif

打开c2java.cpp,键入下面的代码
using namespace std;

int main()
{
	
  JavaVMOption options[1];
  JNIEnv *env;
  JavaVM *jvm;
  JavaVMInitArgs vm_args;
  long status;
  jclass cls;
  jmethodID mid;
  jint square;
  jboolean not;
	jobject jobj;

  options[0].optionString = "-Djava.class.path=.";
  vm_args.version = JNI_VERSION_1_2;
  vm_args.nOptions = 1;
  vm_args.options = options;
  status = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
  if (status != JNI_ERR)
  {
		cls = env->FindClass("com/testJni/testDemo/C2java");
    if(cls !=0)
    { 
				mid = env->GetStaticMethodID( cls, "add", "(II)I");
        if(mid !=0)
        {  
					square = env->CallStaticIntMethod( cls, mid, 5,5);
					std::cout << square << std::endl;
	      }
				mid = env->GetMethodID(cls,"<init>","()V");
				if(mid !=0)
        {  
					jobj=env->NewObject(cls,mid);
					std::cout << "init ok" << std::endl;
	      }
				mid = env->GetMethodID( cls, "judge","(Z)Z");
				if(mid !=0)
        {  
					not = env->CallBooleanMethod(jobj, mid, 1);
					if(!not){
						std::cout << "Boolean ok" << std::endl;
					}
        }
				
    }

    jvm->DestroyJavaVM();
   return 0;
  }
  else
    return -1;

}

下面解释下上面的代码:
JavaVMOption options[] 具有用于 JVM 的各种选项设置。声明的 JavaVMOption options[] 数组足够大,就能容纳我们希望使用的所有选项。在本实例中,我们使用的选项就是类路径选项。
JNIEnv *env 表示 JNI 执行环境。
JavaVM *jvm 是指向 JVM 的指针。我们主要使用这个指针来创建、初始化和销毁 JVM。JavaVMInitArgs vm_args 表示可以用来初始化 JVM 的各种 JVM 参数。
设置参数后,创建我们的jvm :
  status = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
成功返回0,不成功返回JNI_ERR。
创建完成后,我们就可以查找我们的class了,因为我们的java类一般都有包,所以我们也要加上包路径com/testJni/testDemo/C2java

在这里我们会使用到java的一个命令javap ,这个命令有什么用那,我们用javap -s -p C2java看看
c/cpp调用java方法 实例_第4张图片
打开jni.h我们会发现,Signature就是sig,也就是GetStaticMethodID( cls, "add", "(II)I")方法的第三个参数。GetStaticMethodID表示调用static方法,GetMethodID调用普通方法。下面就是传入参数,打出结果。
在看jni.h的时候我们注意到有 CallStaticXXXMethod() 和 CallXXXMethod() 之类的方法。这些方法分别代表调用静态方法和成员方法,用方法的返回类型(例如,Object、Boolean、Byte、Char、Int、Long 等等)代替变量 XXX。
静态方法和普通方法不同之处就是普通方法必须要先实例化一个java对象,调用构造器的时候方法的名称为“<init>”。

下面的代码就不用我再解释了,先是new一个实例出来,然后调用实例的方法。

最后记得销毁jvm。

代码解释完了,我们build下这个工程,生成c2java.exe。

4、运行exe

因为我们生成的exe需要调用jvm.dll初始化,为了使运行的exe不报错误,我们把%JAVA_HOME%/jre/bin/server也加进path目录。方便系统自动搜索jvm.dll。
运行结果:


最后补充:本实例并没有涉及到java的异常、java c/cpp的编码转换问题,对于异常问题,C里没有异常,请使用jni的异常处理函数。编码转换问题上篇已有介绍,此处略去。

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