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的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。