jni/C/CPP调用示例(二)

计划第三篇写一个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
Java代码 复制代码  收藏代码
  1. package com.testJni.testDemo;   
  2.   
  3. public class C2java {   
  4.     public C2java(){   
  5.         super();   
  6.     }   
  7.     public static int add(int a,int b) {   
  8.         return a+b;   
  9.     }   
  10.     public boolean judge(boolean bool) {   
  11.         return !bool;   
  12.     }   
  13.   
  14. }  
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 工程

键入工程名字c2java,点击OK,出来窗口点击next,选取console app

点击完成。到这里先不忙编码实现,我们先把环境搭建好,右键工程属性,选取 linker -->input,在右边窗口添加依赖jvm.lib,这个lib的位置在你%JAVA_HOME%/lib 下。如果你的路径中同我一样包含空格(例如Program Files)记得用引号括起来。

打开stdafx.h文件添加
C++代码 复制代码  收藏代码
  1. #include <iostream>   
  2. #include <jni.h>   
  3.   
  4. #ifdef _WIN32   
  5. #define PATH_SEPARATOR ';'   
  6. #else   
  7. #define PATH_SEPARATOR ':'   
  8. #endif  
#include <iostream>
#include <jni.h>

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

打开c2java.cpp,键入下面的代码
C++代码 复制代码  收藏代码
  1. using namespace std;   
  2.   
  3. int main()   
  4. {   
  5.        
  6.   JavaVMOption options[1];   
  7.   JNIEnv *env;   
  8.   JavaVM *jvm;   
  9.   JavaVMInitArgs vm_args;   
  10.   long status;   
  11.   jclass cls;   
  12.   jmethodID mid;   
  13.   jint square;   
  14.   jboolean not;   
  15.     jobject jobj;   
  16.   
  17.   options[0].optionString = "-Djava.class.path=.";   
  18.   vm_args.version = JNI_VERSION_1_2;   
  19.   vm_args.nOptions = 1;   
  20.   vm_args.options = options;   
  21.   status = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);   
  22.   if (status != JNI_ERR)   
  23.   {   
  24.         cls = env->FindClass("com/testJni/testDemo/C2java");   
  25.     if(cls !=0)   
  26.     {    
  27.                 mid = env->GetStaticMethodID( cls, "add""(II)I");   
  28.         if(mid !=0)   
  29.         {     
  30.                     square = env->CallStaticIntMethod( cls, mid, 5,5);   
  31.                     std::cout << square << std::endl;   
  32.           }   
  33.                 mid = env->GetMethodID(cls,"<init>","()V");   
  34.                 if(mid !=0)   
  35.         {     
  36.                     jobj=env->NewObject(cls,mid);   
  37.                     std::cout << "init ok" << std::endl;   
  38.           }   
  39.                 mid = env->GetMethodID( cls, "judge","(Z)Z");   
  40.                 if(mid !=0)   
  41.         {     
  42.                     not = env->CallBooleanMethod(jobj, mid, 1);   
  43.                     if(!not){   
  44.                         std::cout << "Boolean ok" << std::endl;   
  45.                     }   
  46.         }   
  47.                    
  48.     }   
  49.   
  50.     jvm->DestroyJavaVM();   
  51.    return 0;   
  52.   }   
  53.   else  
  54.     return -1;   
  55.   
  56. }  
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看看

打开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。
运行结果:


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java调用JNI代码需要以下几个步骤: 1.编写C或C++代码实现所需的功能。 2.使用JNI提供的头文件将C或C++代码包装成Java可以调用的本地方法。 3.编译JNI代码生成本地库文件(DLL或SO文件)。 4.在Java代码中使用System.loadLibrary()方法加载本地库文件。 5.通过Java代码调用JNI方法。 下面是一个简单的示例,演示如何在Java中调用C++代码。 首先编写C++代码,实现一个求和函数sum: ```c++ #include <jni.h> JNIEXPORT jint JNICALL Java_Sum_sum(JNIEnv *env, jobject obj, jint a, jint b) { return a + b; } ``` 然后,使用JNI提供的头文件将C++代码包装成Java可以调用的本地方法: ```c++ JNIEXPORT jint JNICALL Java_Sum_sum(JNIEnv *env, jobject obj, jint a, jint b); ``` 其中,Java_Sum_sum是本地方法的名称,参数列表包括JNIEnv *env、jobject obj和jint a、jint b。JNIEnv是一个指向JNI环境的指针,jobject是Java对象的引用。 接下来,编译JNI代码生成本地库文件。在Linux下,可以使用以下命令: ```bash g++ -shared -fpic -I $JAVA_HOME/include -I $JAVA_HOME/include/linux Sum.cpp -o libsum.so ``` 其中,$JAVA_HOME是Java安装目录。 在Windows下,可以使用以下命令: ```bash g++ -shared -I %JAVA_HOME%\include -I %JAVA_HOME%\include\win32 Sum.cpp -o Sum.dll ``` 接下来,在Java代码中使用System.loadLibrary()方法加载本地库文件: ```java System.loadLibrary("sum"); ``` 最后,在Java代码中调用JNI方法: ```java public class Sum { public native int sum(int a, int b); static { System.loadLibrary("sum"); } public static void main(String[] args) { Sum s = new Sum(); System.out.println(s.sum(1, 2)); } } ``` 其中,native关键字表示这是一个本地方法,sum(int a, int b)是Java中调用的方法名。 运行Java代码,输出结果为3,即C++代码实现的求和结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值