您好,欢迎访问三七文档
当前位置:首页 > 临时分类 > 2012自学考试政治《毛邓三》知识点习题7
ava跨平台的特性使Java越来越受开发人员的欢迎,但也往往会听到不少的抱怨:用Java开发的图形用户窗口界面每次在启动的时候都会跳出一个控制台窗口,这个控制台窗口让本来非常棒的界面失色不少。怎么能够让通过Java开发的GUI程序不弹出Java的控制台窗口呢?其实现在很多流行的开发环境例如JBuilder、Eclipse都是使用纯Java开发的集成环境。这些集成环境启动的时候并不会打开一个命令窗口,因为它使用了JNI(JavaNativeInterface)的技术。通过这种技术,开发人员不一定要用命令行来启动Java程序,可以通过编写一个本地GUI程序直接启动Java程序,这样就可避免另外打开一个命令窗口,让开发的Java程序更加专业。JNI答应运行在虚拟机的Java程序能够与其它语言(例如C和C++)编写的程序或者类库进行相互间的调用。同时JNI提供的一整套的API,答应将Java虚拟机直接嵌入到本地的应用程序中。图1是Sun站点上对JNI的基本结构的描述。本文将介绍如何在C/C++中调用Java方法,并结合可能涉及到的问题介绍整个开发的步骤及可能碰到的难题和解决方法。本文所采用的工具是Sun公司创建的JavaDevelopmentKit(JDK)版本1.3.1,以及微软公司的VisualC++6开发环境。环境搭建为了让本文以下部分的代码能够正常工作,我们必须建立一个完整的开发环境。首先需要下载并安装JDK1.3.1,其下载地址为“”。假设安装路径为C:JDK。下一步就是设置集成开发环境,通过VisualC++6的菜单Tools→Options打开选项对话框如图2。将目录C:JDKinclude和C:JDKincludewin32加入到开发环境的IncludeFiles目录中,同时将C:JDKlib目录添加到开发环境的LibraryFiles目录中。这三个目录是JNI定义的一些常量、结构及方法的头文件和库文件。集成开发环境已经设置完毕,同时为了执行程序需要把Java虚拟机所用到的动态链接库所在的目录C:JDKjreinclassic设置到系统的Path环境变量中。这里需要提出的是,某些开发人员为了方便直接将JRE所用到的DLL文件直接拷贝到系统目录下。这样做是不行的,将导致初始化Java虚拟机环境失败(返回值-1),原因是Java虚拟机是以相对路径来寻找所用到的库文件和其它一些相关文件的。至此整个JNI的开发环境设置完毕,为了让此次JNI旅程能够顺利进行,还必须先预备一个Java类。在这个类中将用到Java中几乎所有有代表性的属性及方法,如静态方法与属性、数组、异常抛出与捕捉等。我们定义的Java程序(Demo.java)如下,本文中所有的代码演示都将基于该Java程序,代码如下:packagejni.test;/***该类是为了演示JNI如何访问各种对象属性等*@authorliudong*/publicclassDemo{//用于演示如何访问静态的基本类型属性publicstaticintCOUNT=8;//演示对象型属性publicStringmsg;PRivateint[]counts;publicDemo(){this(缺省构造函数);}/***演示如何访问构造器*/publicDemo(Stringmsg){System.out.println(:+msg);this.msg=msg;this.counts=null;}/***该方法演示如何访问一个访问以及中文字符的处理*/publicStringgetMessage(){returnmsg;}/***演示数组对象的访问*/publicint[]getCounts(){returncounts;}/***演示如何构造一个数组对象*/publicvoidsetCounts(int[]counts){this.counts=counts;}/***演示异常的捕捉*/publicvoidthrowExcp()throwsIllegalaccessException{thrownewIllegalAccessException(exceptionoccur.);}}初始化虚拟机本地代码在调用Java方法之前必须先加载Java虚拟机,而后所有的Java程序都在虚拟机中执行。为了初始化Java虚拟机,JNI提供了一系列的接口函数InvocationAPI。通过这些API可以很方便地将虚拟机加载到内存中。创建虚拟机可以用函数jintJNI_CreateJavaVM(JavaVM**pvm,void**penv,void*args)。对于这个函数有一点需要注重的是,在JDK1.1中第三个参数总是指向一个结构JDK1_1InitArgs,这个结构无法完全在所有版本的虚拟机中进行无缝移植。在JDK1.2中已经使用了一个标准的初始化结构JavaVMInitArgs来替代JDK1_1InitArgs。下面我们分别给出两种不同版本的示例代码。在JDK1.1初始化虚拟机:#includeintmain(){JNIEnv*env;JavaVM*jvm;JDK1_1InitArgsvm_args;jintres;/*IMPORTANT:版本号设置一定不能漏*/vm_args.version=0x00010001;/*获取缺省的虚拟机初始化参数*/JNI_GetDefaultJavaVMInitArgs(&vm_args);/*添加自定义的类路径*/sprintf(classpath,%s%c%s,vm_args.classpath,PATH_SEPARATOR,USER_CLASSPATH);vm_args.classpath=classpath;/*设置一些其他的初始化参数*//*创建虚拟机*/res=JNI_CreateJavaVM(&jvm,&env,&vm_args);if(res0){fprintf(stderr,Can'tcreateJavaVM);exit(1);}/*释放虚拟机资源*/(*jvm)-DestroyJavaVM(jvm);}JDK1.2初始化虚拟机:/*invoke2.c*/#includeintmain(){intres;JavaVM*jvm;JNIEnv*env;JavaVMInitArgsvm_args;JavaVMOptionoptions[3];vm_args.version=JNI_VERSION_1_2;//这个字段必须设置为该值/*设置初始化参数*/options[0].optionString=-Djava.compiler=NONE;options[1].optionString=-Djava.class.path=.;options[2].optionString=-verbose:jni;//用于跟踪运行时的信息/*版本号设置不能漏*/vm_args.version=JNI_VERSION_1_2;vm_args.nOptions=3;vm_args.options=options;vm_args.ignoreUnrecognized=JNI_TRUE;res=JNI_CreateJavaVM(&jvm,(void**)&env,&vm_args);if(res0){fprintf(stderr,Can'tcreateJavaVM);exit(1);}(*jvm)-DestroyJavaVM(jvm);fprintf(stdout,JavaVMdestory.);}为了保证JNI代码的可移植性,建议使用JDK1.2的方法来创建虚拟机。JNI_CreateJavaVM函数的第二个参数JNIEnv*env,就是贯穿整个JNI始末的一个参数,因为几乎所有的函数都要求一个参数就是JNIEnv*env。访问类方法初始化了Java虚拟机后,就可以开始调用Java的方法。要调用一个Java对象的方法必须经过几个步骤:1.获取指定对象的类定义(jclass)有两种途径来获取对象的类定义:第一种是在已知类名的情况下使用FindClass来查找对应的类。但是要注重类名并不同于平时写的Java代码,例如要得到类jni.test.Demo的定义必须调用如下代码:jclasscls=(*env)-FindClass(env,jni/test/Demo);//把点号换成斜杠然后通过对象直接得到其所对应的类定义:jclasscls=(*env)-GetObjectClass(env,obj);//其中obj是要引用的对象,类型是jobject2.读取要调用方法的定义(jmethodID)我们先来看看JNI中获取方法定义的函数:jmethodID(JNICALL*GetMethodID)(JNIEnv*env,jclassclazz,constchar*name,constchar*sig);jmethodID(JNICALL*GetStaticMethodID)(JNIEnv*env,jclassclass,constchar*name,constchar*sig);这两个函数的区别在于GetStaticMethodID是用来获取静态方法的定义,GetMethodID则是获取非静态的方法定义。这两个函数都需要提供四个参数:env就是初始化虚拟机得到的JNI环境;第二个参数class是对象的类定义,也就是第一步得到的obj;第三个参数是方法名称;最重要的是第四个参数,这个参数是方法的定义。因为我们知道Java中答应方法的多态,仅仅是通过方法名并没有办法定位到一个具体的方法,因此需要第四个参数来指定方法的具体定义。但是怎么利用一个字符串来表示方法的具体定义呢?JDK中已经预备好一个反编译工具javap,通过这个工具就可以得到类中每个属性、方法的定义。下面就来看看jni.test.Demo的定义:打开命令行窗口并运行javap-s-pjni.test.Demo得到运行结果如下:CompiledfromDemo.javapublicclassjni.test.Demoextendsjava.lang.Object{publicstaticintCOUNT;/*I*/publicjava.lang.Stringmsg;/*Ljava/lang/String;*/privateintcounts[];/*[I*/publicjni.test.Demo();/*()V*/publicjni.test.Demo(java.lang.String);/*(Ljava/lang/String;)V*/publicjava.lang.StringgetMessage();/*()Ljava/lang/String;*/publicintgetCounts()[];/*()[I*/publicvoidsetCounts(int[]);/*([I)V*/publicvoidthrowExcp()throwsjava.lang.IllegalAccessException;/*()V*/static{};/*()V*/}我们看到类中每个属性和方法下面都有一段注释。注释中不包含空格的内容就是第四个参数要填的内容(关于javap具体参数请查询JDK的使用帮助)。下面这段代码演示如何访问jni.test.Demo的getMessage方法:/*假设我们已经有一个jni.test.Demo的实例obj*/jmethodIDmid;jclasscls=(*env)-GetObjectClass(env,obj);//获取实例的类定义mid=(*env)-GetMethodID(env,cls,getMessage,()Ljava/lang/String;);/*假如mid为0表示获取方法定义失败*/jstringmsg=(*env)-CallObjectMethod(env,obj,mid);/*假如该方法是静态的方法那只需要将最后一
本文标题:2012自学考试政治《毛邓三》知识点习题7
链接地址:https://www.777doc.com/doc-3006804 .html