Java跨平台的特性使Java越来越受开发人员的欢迎,但也往往会听到不少的抱怨:用Java开发的图形用户窗口界面每次在启动的时候都会跳出一个控制台窗口,这个控制台窗口让本来非常棒的界面失色不少。怎么能够让通过Java开发的GUI程序不弹出Java的控制台窗口呢?
其实现在很多流行的开发环境例如JBuilder、Eclipse都是使用纯Java开发的集成环境。这些集成环境启动的时候并不会打开一个命令窗口,因为它使用了JNI(Java Native Interface)的技术。
通过这种技术,开发人员不一定要用命令行来启动Java程序,可以通过编写一个本地GUI程序直接启动Java程序,这样就可避免另外打开一个命令窗口,让开发的Java程序更加专业。
JNI允许运行在虚拟机的Java程序能够与其它语言(例如C和C++)编写的程序或者类库进行相互间的调用。同时JNI提供的一整套的API,允许将Java虚拟机直接嵌入到本地的应用程序中。
其实C++中调用JAVA的本质就是在C++中运行JAVA虚拟机。
环境搭配:
测试环境:VC++6.0,Eclipse 3.4,JDK 1.6.
配置环境变量:C:/Program Files/Java/jdk1.6.0_21/jre/bin/server加入到环境变量path中去。
同时将C:/Program Files/Java/jdk1.6.0_21/include与C:/Program Files/Java/jdk1.6.0_21/include/win32加入到 工具->选择->目录->Include files下。再将C:/Program Files/Java/jdk1.6.0_21/lib加入到 工具->选择->目录->Library files下。
在运行的时候别忘记了把jvm.dll链接进去:工程->设置->Link把jvm.dll加进去。
下面是一个C++调用JAVA的例子:
JAVA代码:
ublic class work {
public int x11=10;
public double x12=20.3;
public static int x21=100;
public static String x22="xx";
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("In java: C++ invoke JAVA");
int sum=new work().add(3, 5);
System.out.println("结果是:"+sum);
}
public int add(int x,int y){
int sum=0;
sum=x+y;
return sum;
}
public void xx(int x,int y){
System.out.println("C++中调用java中的非静态方法");
}
public static int xx (double x, int y){
int sum=0;
System.out.println("C++调用java中的静态方法");
return sum;
}
}
C++代码:
#include "jni.h"
#include <iostream.h>
#include <string.h>
jobject getInstance(JNIEnv* env, jclass obj_class);
//C++中调用java也就是调用java虚拟机来运行java程序
int main(){
JNIEnv *env;
JavaVM *jvm;
jint res;
jclass cls;
jobject obj;
jmethodID mid;
JavaVMInitArgs vm_args;
JavaVMOption options[3];
memset(&vm_args,0,sizeof(vm_args));
//进行初始化工作,C++调用java执行
options[0].optionString="-Djava.compiler=NONE";
options[1].optionString="-Djava.class.path==.;C://";
options[2].optionString="-verbose:jni";
vm_args.version=JNI_VERSION_1_4;
vm_args.nOptions=3;
vm_args.options=options;
vm_args.ignoreUnrecognized=JNI_TRUE;
res=JNI_CreateJavaVM(&jvm,(void**)&env,&vm_args);//创建JAVA虚拟机
cout<<res<<endl;
if(res>=0){
cout<<res<<endl;
}
//调用java中的main方法
cls=env->FindClass("work");
mid=env->GetStaticMethodID(cls,"main","([Ljava/lang/String;)V");
env->CallStaticVoidMethod(cls,mid,NULL);
//调用java中的非静态方法
obj=getInstance(env,cls);
jmethodID mid1=env->GetMethodID(cls,"xx","(II)V");
env->CallVoidMethod(obj,mid1,NULL);//调用非静态方法,传的是对象,调用静态方法传的是类名
//调用java中的静态方法
jmethodID mid2=env->GetStaticMethodID(cls,"xx","(DI)I");
env->CallStaticIntMethod(cls,mid2,NULL);//传的是类名
//得到非静态变量的值
//先得到field的ID,再得到field的值
jfieldID fid=env->GetFieldID(cls,"x11","I");
jint x11=env->GetIntField(obj,fid);
cout<<"非静态整形变量x11的值为:"<<x11<<endl;
jfieldID fid2=env->GetFieldID(cls,"x12","D");
jdouble x12=env->GetDoubleField(obj,fid2);
cout<<"非静态double型变量x12的值为:"<<x12<<endl;
//得到静态变量的值
jfieldID staticintfid=env->GetStaticFieldID(cls,"x21","I");
jint x21=env->GetStaticIntField(cls,staticintfid);
cout<<"静态整形变量x21的值为:"<<x21<<endl;
jvm->DestroyJavaVM();//销毁JAVA虚拟机
return 0;
}
jobject getInstance(JNIEnv* env,jclass obj_class){//调用构造方法建立对象
jmethodID construction_id=env->GetMethodID(obj_class,"<init>","()V");//init是构造方法
jobject obj=env->NewObject(obj_class,construction_id);
return obj;
}
解释一下:
options[1].optionString="-Djava.class.path==.;C://";
其中C://是你放.java的路径,在这里就是work.java放到C:/work.java.
如果在运行过程中找不到jvm.dll文件的话,在确保环境变量配置正确的情况下,就是找不到jvm.dll,我的解决方法是把所有的JDK,JRE重装了一下。因为如果你的系统中有几个JRE或者JDK的话,那么程序就不知道找哪一个了。就有可能出现找不到的情况。以上是我学习JNI的一点总结,希望大家给予批评指正。