用Jace整合Java和C++
当前位置:以往代写 > JAVA 教程 >用Jace整合Java和C++
2019-06-14

用Jace整合Java和C++

用Jace整合Java和C++

副标题#e#

摘要

Jace是一种免费的开放源代码的东西,它使我们可以或许轻松地开拓JNI(Java本机接口)代码。本篇文章具体地阐明白JNI API的问题,以及如何利用Jace办理这些问题。

假如没有更深的相识,我们必然会觉得Sun设计JNI的目标是为了不让Java编程人员利用它。究竟,范例安详形同虚设,缺乏错误查抄机制,举办一次简朴的Java要领挪用需要4次或更多的JNI挪用,这都是JNI明明的不敷之处。别的,我们还必需打点JNIEnv指针,不能在多个线程中利用JNI挪用,必需为每种大概的操纵在9个函数挪用中举办选择,并且异常信息的获取也很是地坚苦。这还只是JNI所呈现问题的一部门,我们还能发明很多其他问题。

这些限制中的很多部份都与JNI与C语言的绑定有关,C语言自己对范例安详、异常处理惩罚机制的支持也很是欠好。尽量今朝大大都的编程人员都已经可以或许利用C++编写代码,但Sun没有放弃C编程人员,这也是JNI今朝这种状况的原因。不幸的是,这种很难利用的API给开拓人员带来了很多坚苦。

Jace是一款免费的开放源代码的东西包,旨在使JNI编程变得越发简朴。它支持由Java类文件自动生成C++署理类以及C++与Java的异常、数组、包、工具的整合,打点Java引用的线程绑定和生命周期。更为重要的是,它可以或许使我们开拓更小、更易于领略、在编译时范例安详的模块。

JNI的范例系统

Jace最根基的特点是它利用C++署理类来表达Java范例。为了真正地领略署理类的利益,我们首先需要来看看JNI的范例系统。Sun在JNI中利用了24种C范例来暗示所有大概的Java范例。JNI包括有9个简朴范例:

·jboolean

·jbyte

·jchar

·jshort

·jint

·jlong

·jdouble

·jfloat

·void

JNI有14种引用范例,如下图所示:

用Jace整合Java和C++

(图:picture01)

别的,JNI有一个复合型的范例jvalue,它可以或许表达所有的简朴和引用范例。


#p#副标题#e#

Jace范例系统

图2暗示根基的Jace数据范例的类图表。这些类是我们会见Jace运行时间库的简朴的接口,它与JNI的数据范例对应很是细密。

用Jace整合Java和C++

(图:picture02)

Jace的数据范例系统是直接以24种JNI数据范例为基本的,对付每一种JNI数据范例而言,Jace都有一个相应的C++署理类。9种JNI简朴数据范例以及jvalue、jclass、jobject、jstring和jthrowable都直接映射为相应的Jace署理类,JNI的jarray数据范例以及9个派生的数组数据范例都被映射为一种基于模板的JArray数据范例。在下面的部门中,我们将对每种C++署理类举办具体的表明。

简朴类

9个简朴的类可以作为9种JNI的简朴数据范例的封装器。我们可以将这些类作为参数,并返回其他C++署理类的值:

/* 得到值为“A String”的java.lang.String的哈希码值
*/
JInt hashCode = String( "A String" ).hashCode();

我们也可以将这些类作为JArray类的模板参数:

/* 建设一个巨细为512的字节缓冲区
*/
JArray<JByte> buffer( 512 );

JValue

JValue是所有署理类的基本类,它可以或许表达Java所有的简朴和引用数据范例。每个JValue有一个JClass,该JClass暗示jvalue相应的jclass。我们只能提供一个JNI的jvalue数据范例构建JValue,JValue就成为了jvalue的持有者。大大都开拓人员无需与JValues直接打交道。

JClass

JClass暗示JNI的数据范例jclass,它提供了会见其jclass和在差异的JNI挪用中暗示jclass的字符串(譬喻,java/lang/Object和Ljava/lang/Object)。Jace的框架利用JClass实例提供举办GetMethodID()、GetFieldID()和NewObjectArray()等JNI挪用所必须的信息。大大都开拓人员无需直接与JClass打交道。

JObject

JObject类暗示JNI的数据范例jobject,并作为所有引用数据范例的基本类。除了最重要的JValue::getJavaValue()外,JObject类还提供了getJavaObject()要领。除了getJavaObject()可以或许解开jvalue,并将它放在jobject中外,这二个要领的成果相当。

JObject较量有趣,因为Java的引用范例有一些Java的简朴数据范例所不具备的特性:

·引用范例没有本身的值,它们只是指向这些值。我们可以用二种方法构建JObject子类。第一种方法,我们可以将它构建为现有Java工具的引用。通过利用接管jobject(或包括jobject的jvalue)为参数的构建器可能利用C++的拷贝构建器,我们就可以以这种方法构建JObject子类。

在对JObject子类实例化时,子类实例将它本身提交给作为参数提供的jobject引用。(实例利用NewGlobalRef()建设jobject的全局性引用。)

using jace::java::net::URL;

JNIEXPORT void JNICALL Java_foo_Bar_someMethod( JNIEnv *env, jobject jURL ) {

#p#分页标题#e#

/* 建设jURL的一个引用,而不是一个新的URL
*/
URL url( jurl );
  /* 既然已经实例化了C++署理工具,我们就就可以利便地对jURL挪用toString()等要领
*/
std::string urlString = url.toString();
}

#p#副标题#e#

第二种要领,我们可以通过建设一个新的Java工具来构建JObject子类。可以通过挪用其他子类的构建器建设新的工具,子类可以利用JNI挪用符合的Java构建器。在构建Java工具后,子类就会建设一个新的指向它的全局性引用:

/* 在foo.txt上建设一个新的FileOutputStream。
*/
jace::java::io::FileOutputStream output( "foo.txt" );

无论如何建设JObject子类,子类独一的操纵是对在构建时建设的全局性引用挪用DeleteGlobalRef()。

·引用范例的数据大概是空值,通过挪用JObject::isNull(),我们可以检测C++署理类是否指向一个为空值的Java工具:

JNIEXPORT void JNICALL Java_foo_Bar_someMethod( JNIEnv *env, jstring
javaString ) {
  String str( javaString );
  if ( str.isNull() ) {
cout << "Error - The argument, javaString, must not be
null." << endl;
}
}

Throwable和String

Throwable和String C++署理类都是由JObject派生的(与所有的引用范例的署理类一样),它们(尚有其他一些类)是Jace库的焦点部份,向用户提供C++和Java之间更细密的整合本领。

Jace的成果

Jace可以提供很多成果,个中包罗线程打点、异常打点、自动范例转换和其他一些成果。下面我们来接头这些成果:

线程打点

在JNI中存在着一些线程方面的问题:

·JNIEnv指针只能在得到它们的线程上利用。

·大大都的JNI数据范例只能在它们存在的线程上利用。

·在挪用JNI函数之前,C++线程必需毗连到JVM上

Jace办理了这些问题。第一,Jace库中的每个函数自动地得到一个只能在当前线程上利用的JNIEnv指针。第二,Jace建设须要的JNI范例的全局性引用。譬喻,JClass建设其jclass成员的全局性引用,JObject建设其jobject成员的全局性引用。与只能供当前线程利用的局部性引用差异的是,全局性变量可以或许供所有线程利用。

最后,Jace中的每个函数可以或许确保在挪用JNI函数之前,当前的线程可以或许毗连到JVM上。

#p#副标题#e#

异常打点

异常处理惩罚是JNI编程的一个短肋。在异常处理惩罚方面,Jace有二条目的:

1)Jace查抄它执行的每个JNI函数的返回码。假如有错误产生,Jace排除JNI异常,然后发出Jace的JNIException动静。

2)假如由于要领发出异常动静,Jace发明Java要领的挪用失败,Jace则查抄并排除JNI异常,然后建设该异常的一个C++署理实例,并发出C++署理。

using namespace jace::java::net;
  void readGoogle() {
try {
/* 当Jace在内部执行NewObject时,它会查抄是否有异常产生,
* 假如JNI函数ExceptionOccurred返回一个异常,则Jace排除
* 该异常,建设一个相应的C++署理,并发出它。
*/
URL url( "http://www.google.com" );
}
/* 在这里,我们可以得到Jace发出的C++署理异常
*/
catch ( MalformedURLException& e ) {
cout << e;
}
}

自动范例转换

Jace提供C++和Java简朴数据范例之间的自动数据范例转换。我们可以在C++署理需要java::lang::String的处所利用C++的std::string或char*,我们也可以在C++署理要领需要JBoolean、JInt和JChar简朴JNI数据范例的处所利用bool、int和char等C++数据范例:

using jace::javax::swing::JFrame;
  JFrame createFrame( const std::string& title, int x, int y ) {
  /* JFrame的原型是JFrame( java::lang::String str );,
* Jace自动地在std::string和java::lang::String之间举办转换。
*/
JFrame frame( title );
  /* setLocation的原型是setLocation( JInt x, JInt y );,
* Jace自动地在int之间JInt举办转换。
*/
frame.setLocation( x , y );
return frame;
}

C++集成

Jace包罗C++署理生成东西━━BatchGen,Jace开拓人员对Java运行时间库情况(JRE)的rt.jar利用BatchGen生成C++署理类。Jace开拓人员已经对这些生成的署理类举办修改,以更好地与C++语言和尺度库举办集成。

譬喻,java.lang.Object有一个附加的操纵符<<(ostream& out, Object& object),java.lang.String也有一些包罗+()、=()和==()在内的附加要领,可以使它与std::strings和char*s更好地举办集成。

范例安详字段和要了解见

#p#分页标题#e#

C++的署理生成是Java工具范例安详会见的基本。对付给定的Java类文件,Jace可以或许生成完全沟通的要领和字段的C++署理类,我们可以以与挪用Java中雷同要领沟通的方法挪用C++署理要领,字段是通过同名的要领举办会见的:

/* 一个Java类
*/
public class Foo {
public int aField;
public String aMethod( URL aURL );
}
  /* 从C++中会见C++署理
*/
Foo foo;
foo.aField() = 14;
String result = foo.aMethod( URL( "http://www.google.com" ) );

Jace提供了二种东西━━ProxyGen和BatchGen,我们可以用这二种东西从Java类文件中生成C++署理类。

#p#副标题#e#

范例安详数组

我们可以利用Jace的模板JArray类会见Java的数据范例安详数组。按照数组的数据范例,Jace挪用符合的Get<Type>ArrayElement()和Set<Type>ArrayElement() JNI函数:

JArray<JInt> intArray( 10 ); // 导致对NewIntArray的挪用
int i = intArray[ 2 ]; // 导致对GetIntArrayElements和应用
  JArray<String> stringArray( 5 ); // 导致对NewObjectArray的挪用
std::string str = stringArray[ 2 ]; // 导致对GetObjectArrayElement的挪用

Jace东西

ProxyGen和BatchGen可以用来生成C++署理类。ProxyGen用来处理惩罚一个类文件,BatchGen则用来处理惩罚一个jar文件中所有的类。

ProxyGen

ProxyGen可以或许将一个Java类文件的头部文件或源文件转出到尺度输出。ProxyGen老是会包括生成的C++署理类中的public要领和字段,按照指定的会见程度,它也会包括protected、package或private要领和字段。

用法:ProxyGenerator <类文件> <头部 | 源文件> [ 选项 ]

选项大概是:

-protected :生成protected字段和成员

-package :生成package字段和成员

-private :生成private字段和成员

BatchGen

在生成C++署理类的头文件和源代码文件方面,BatchGen与ProxyGen很是相似。二者的差异之处是,ProxyGen只处理惩罚一个Java类文件,BatchGen则处理惩罚由多个Java类文件构成的jar或zip文件。别的,ProxyGen将头文件和源代码文件输出到尺度输出,BatchGen则将头文件和源代码文件输出到指定的目次。

用法:BatchGenerate <包括Java类的jar或zip>

<头文件的方针目次>
<源代码文件的方针目次>
[ 选项 ]
选项大概是:
-protected :生成protected的字段和成员
-package :生成package字段和成员
-private :生成private字段和成员

Jace还会有哪些改造

未来,Jace的机能会进一步地提高,对数组提供更好的支持,虽然了,在其他一些方面也会有所改造。譬喻,Jace将把Java的数组作为尺度的C++容器,并兼容for_each()等函数。别的,它还会支持数组元素的靠山缓冲和预先取等成果。

结论

JIN存在的很多问题都与它和C的绑定有关,通过将JNI与C++绑定,Jace很好地办理了JNI存在的问题,将有助于Java的普及。

    关键字:

在线提交作业