jni教程,jni使用步骤

  jni教程,jni使用步骤

  在研究了JNI之后,当我发表这篇文章时,我不知道该选择什么。我不知道JNI应该属于哪一类

  1 .简介

  JNI是Java本地接口的缩写。它旨在:

  标准Java类库可能不支持您的应用程序所需的平台相关特性。

  您可能已经有了用另一种编程语言编写的库或应用程序,并且希望Java应用程序可以访问它

  您可能希望用低级编程语言(如汇编语言)实现一小部分时间关键的代码,然后让您的Java应用程序调用这些函数

  2.2的写作步骤。调用

  用本机声明的方法编写java类。

  使用javac命令编译java类。

  用javah?Jni java类名生成扩展名为h的头文件。

  使用C/C实现本地方法

  用C/C写的文件生成动态链接库。

  好的

  1)编写java程序:

  以HelloWorld为例。

  代码1:

  HelloWorld类{

  public native void display hello world();

  静态{

  system . loadlibrary( hello );

  }

  公共静态void main(String[] args) {

  新HelloWorld()。display hello world();

  }

  }

  声明本机方法:如果要将某个方法用作本地方法,必须声明该方法应该是本机的,并且不能实现。稍后将描述该方法的参数和返回值。

  动态库:system . loadlibrary( hello );加载动态库(我们可以这样理解:我们的方法displayHelloWorld()没有实现,但是我们直接在下面使用,所以在使用之前必须初始化)。一般来说,它在这里是作为静态块加载的。同时需要注意的是system . loadlibrary();的参数“hello”是动态库的名称。

  Main()方法

  2)关于编译没什么好说的了

  贾瓦茨HelloWorld.java

  3)生成扩展名为h的头文件。

  贾瓦?jni HelloWorld

  头文件的内容:

  /*不要编辑此文件-它是机器生成的*/

  #包含jni.h

  HelloWorld类的头*/

  #ifndef _Included_HelloWorld

  #define _Included_HelloWorld

  #ifdef __cplusplus

  外部 C {

  #endif

  /*

  *类别:HelloWorld

  *方法:displayHelloWorld

  *签名:()V

  */

  JNI export void JNI call Java _ hello world _ display hello world

  (JNIEnv *,job object);

  #ifdef __cplusplus

  }

  #endif

  #endif

  (这里我们可以这样理解:这个H文件相当于我们在java中的接口,这里声明了一个Java _ Hello World _ Display Hello World(JNIENV *,job project);方法,然后在我们的本地方法中实现这个方法,也就是说我们写C/C程序时用的方法名必须和这里的一样)。

  4)编写本地方法。

  使用与javah命令生成的头文件中声明的方法名相同的方法名实现该方法。

  代码2:

  1 #包含jni.h

  2 #包含“HelloWorld.h”

  3 #包含stdio.h

  4 JNI export void JNI call Java _ hello world _ display hello world(JNI env * env,jobject obj)

  {

  printf(Hello world!\ n’);

  返回;

  }

  请注意代码2中的第一行。需要导入文件jni.h(这个文件可以在%JAVA_HOME%/include文件夹下找到),因为JNIEnv、jobject等类型。在程序中都是在这个头文件中定义的;另外,在第二行,我们需要引入HelloWorld.h头文件(这是我的理解:相当于我们在编写java程序的时候,需要声明一个接口。这里实现了HelloWorld.h头文件中声明的方法。当然不一定是这样)。然后另存为HelloWorldImpl.c就ok了。

  5)生成动态库。

  例如,在Windows中,需要生成一个dll文件。在保存HelloWorldImpl.c的文件夹下,使用VC的编译器cl。

  cl-I % Java _ home % \ include-I % Java _ home % \ include \ win32-LD hello world imp . c-Fe hello . dll

  注意:生成的dll文件名配置在选项-Fe之后,这里是hello,因为我们在HelloWorld.java文件中加载库时使用的名字是hello。当然,这里修改后,那里也需要修改。此外,还需要添加-I % Java _ home % \ include-I % Java _ home % \ include \ Win32参数,因为jni.h文件是在第四步编写本地方法时引入的。

  6)运行程序。

  Java HelloWorld还可以。^_^

  3.Java类型对应于本地类型

  在下列情况下,如果你需要在本地方法中应用java对象的引用,你将使用类型之间的转换:

  1)参数被传入1)java方法中的本地方法;

  2)在本地方法中创建java对象;

  3)在本地方法中将结果返回给java程序。

  它分为以下两种情况:

  原始Java类型

  原始类型,如布尔、整数、浮点等。从java程序传递到本地方法可以直接使用。下面是Java中的原始类型和本地方法中的类型之间的对应关系:

  类型Java本地类型字节(位)

  布尔型jboolean 8,无符号

  字节jbyte 8

  char jchar 16,无符号

  短jshort 16

  int jint 32

  龙江64

  浮动jfloat 32

  double jdouble 64

  无效无效不适用

  也就是说,如果我在方法中传入一个布尔参数,那么我在局部方法中就有一个与之对应的jboolean类型。类似地,如果在本地方法中返回一个jint,那么在java中返回一个int类型。

  Java对象

  Java对象作为引用传递给本地方法,这些Java对象的所有引用都有一个共同的父类型JobProject(相当于Java中的job object类是所有类的父类)。以下是JNI实现的job object的一些子类:

  4.在本地方法中访问java程序的内容

  1)访问字符串对象:

  从java程序传递的String对象对应于本地方法中的jstring类型。jstring类型与C中的char*不同,所以如果直接把它当作char*使用,会得到一个错误。因此,在使用jstring之前,需要在c/c中将它转换成char*。这里使用JNIEnv的方法进行转换。下面是一个例子:

  代码3:

  JNI export jstring JNI call Java _ Prompt _ getLine

  (JNIEnv *env,jobject obj,jstring提示)

  {

  char buf[128];

  const char * str=(* env)-GetStringUTFChars(env,prompt,0);

  printf(%s ,str);

  (* env)-ReleaseStringUTFChars(env,prompt,str);

  这里,GetStringUTFChars方法用于将传入的提示(jstring类型)转换为UTF-8格式,这种格式可以在本地方法中使用。

  注意:使用转换后的对象后,需要显示调用ReleaseStringUTFChars方法的空间,让JVM释放转换成UTF-8字符串的对象。如果不显示调用,对象将一直保存在JVM中,不会被垃圾收集器收集,这将导致内存溢出。

  以下是访问字符串的一些方法:

  GetStringUTFChars将jstring转换成UTF 8格式的char*

  GetStringChars将jstring转换成Unicode格式的char *

   releasestringutchar释放指向UTF-8格式的char*的指针。

  ReleaseStringChars以Unicode格式释放指向char*的指针。

  NewStringUTF创建UTF 8格式的字符串对象。

  NewString创建Unicode格式的字符串对象。

  getstringutflengt获取UTF 8格式的char*的长度。

  GetStringLength获取Unicode格式的char*的长度

  2)访问数组对象:

  和String对象一样,jarray对象不能在本地方法中直接访问,但是使用了JNIEnv指针指向的一些方法。

  访问Java原始类型数组:

  1)获取数组的长度:

  代码4:

  JNI export jint JNI call Java _ IntArray _ sumArray

  (JNIEnv *env,jobject obj,jintArray arr)

  {

  int i,sum=0;

  jsize len=(* env)-GetArrayLength(env,arr);

  如代码4所示,这里采集数组的长度不同于普通C语言中的长度。这里,我们使用GetArrayLength,JNIEvn的一个函数。

  2)获取指向数组元素的指针:

  代码4:

  jint * body=(* env)-GetIntArrayElements(env,arr,0);

  使用GetIntArrayElements方法获取指向arr数组元素的指针。注意这个函数的参数。第一个是JNIEnv,第二个是数组,第三个是数组中的第一个元素。

  3)使用指针取出数组中的元素

  代码5:

  for(I=0;i i ) {

  sum=body[I];

  }

  这里的用法和普通c中数组的用法没什么区别。

  4)释放数组元素的引用

  代码6:

  (* env)-ReleaseIntArrayElements(env,arr,body,0);

  和释放操作字符串中String的引用一样,提醒JVM回收arr数组元素的引用。

  这里的例子使用了一个int数组,以及相应的数组,如boolean和float。

  获取数组元素指针的对应关系:

  函数数组类型

  GetBooleanArrayElements布尔值

  GetByteArrayElements字节

  GetCharArrayElements char

  GetShortArrayElements short

  GetIntArrayElements int

  GetLongArrayElements long

  GetFloatArrayElements浮动

  GetDoubleArrayElements double

  释放数组元素指针的对应关系:

  函数数组类型

  ReleaseBooleanArrayElements布尔值

  ReleaseByteArrayElements字节

  ReleaseCharArrayElements char

  ReleaseShortArrayElements短

  ReleaseIntArrayElements int

  ReleaseLongArrayElements long

  ReleaseFloatArrayElements浮动

  ReleaseDoubleArrayElements double

  访问自定义Java对象数组

  JNI提供了一组独立的函数来访问对象数组的元素。您可以使用这些函数来获取和设置单个对象数组元素。

  注意:你不能一次得到所有的对象数组元素。

  GetObjectArrayElement返回给定索引处的对象元素。

  SetObjectArrayElement更新给定索引处的object元素。

  3)访问Java对象的方法:

  要在本地方法中调用Java对象的方法:

  .获取您需要访问的Java对象的类:

  jclass cls=(* env)-get object class(env,obj);

  使用GetObjectClass方法获取obj对应的jclass。

  .获取MethodID:

  jmethodID mid=(* env)-get method id(env,cls, callback ,(I)V );

  使用GetMethdoID方法获取要使用的方法的MethodID。其参数的含义:

  env?JNIEnv

  cls?第一步中获得的jclass

  回电?要调用的方法的名称

  (一)五?方法的签名

  通话方式:

  (*env)- CallVoidMethod(env,obj,mid,depth);

  使用CallVoidMethod方法调用该方法。参数的含义:

  env?JNIEnv

  obj?通过本地方法进行作业对象

  mid?要调用的MethodID(即在第二步中获得的MethodID)

  深度?方法所需的参数(对应于方法的要求,添加相应的参数)

  注意:这里使用的是CallVoidMethod方法调用,因为没有返回值。如果有返回值,就用对应的方法,后面会提到。

  方法的签名

  方法的签名由方法的参数和返回值的类型组成。以下是它们的结构:

  (参数类型)返回类型

  Java程序中的参数类型及其对应的值如下:

  签名Java中的类型

  z布尔型

  b字节

  字符

  它很短

  整形

  j龙

  f浮动

  d双精度

  l完全合格级;完全合格级

  [类型类型[]

  (参数类型)ret-type方法类型

  Java类的方法签名可以通过javap命令获得:

  Java类名

  将参数传递给被调用的函数:

  通常,我们在methodID后直接添加要传递的参数,但是还有其他传递参数的方法:

  CallVoidMethodV可以获取可变数量的列表作为参数;

  CallVoidMethodA可以获得联合。

  调用静态方法:

  将第二步和第三步中调用的方法改为相应的方法:

  GetStaticMethodID获取相应静态方法的ID。

  CallStaticIntMethod调用静态方法

  调用超类的方法:

  用的比较少。你自己看吧。^_^。

  4)访问Java对象的属性:

  访问Java对象的属性基本上与访问Java对象相同。您只需要在function to字段中更改方法(当然,没有

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: