`
mmdev
  • 浏览: 12915142 次
  • 性别: Icon_minigender_1
  • 来自: 大连
文章分类
社区版块
存档分类
最新评论

技术转载:Jni学习四:如何编写jni方法

 
阅读更多

转载:http://blog.chinaunix.net/u1/38994/showart_1099528.html


一、概述:

在这篇文章中将会简单介绍如何编制一些简单的JNI方法。我们都知道JNI方法可以帮助我们调用用C/c++编写的函数,这样如果一项工作已经用C/c++语言实现的话,我们就可以不用花很大的力气再用JAVA语言对这一工作进行再实现,只要编制相应的JNI函数,就可以轻松实现JAVA语言对C/c++函数的调用,从而大大减轻程序开发人员的工作量。

在这个项目中,我们编制了很多小实例,通过阅读,运行这些小实例,你可以轻松的学会如何编制JNI方法。这篇文档可以帮助你更好的理解及实现这些实例。

现在让我们进入主题。首先,我们看一下这个项目的体系构架。该项目分为两部分,一部分用c语言是c语言的例子,另一部分是c++语言的例子。每部分都包含java,src源文件目录,以及一个Makefile文件。java目录中是需要调用JNI函数的JAVA源程序,含有后缀名.java。src目录中含有JNI函数的实现代码,包括.c或.cpp文件和.h文件。Makefile文件是对java、src目录下的文件进行编译组织进而生成可执行文件的文件。当Makefile文件执行以后还会生成以下子目录:lib,class,bin目录。lib目录中包含项目中生成的静态函数库文件libJNIExamples.so,java程序所调用的JNI方法都是通过这个库来调用的。class目录中包含由java目录下的.java文件生成的.class文件。bin目录中是一个可执行的shell脚本文件。在执行该脚本的时候,项目所有程序实例的运行结果都将一并显示在屏幕上。


具体执行步骤为:

make

cdbin

./run.sh


下面来介绍一下在这个项目中所实现的实例:

1.如何调用标准C/c++中的函数--例如:printf(...)
2.如何调用C/c++中自定义的函数
3.如何在jni函数中访问java类中的对象实例域
4.如何在jni函数中访问java类中的静态实例域
5.如何在jni函数中调用java对象的方法
6.如何在jni函数中调用java类的静态方法
7.如何在jni函数中传递基本数据类型参数
8.如何在jni函数中传递对象类型参数
9.如何在jni函数中处理字符串
10.如何在jni函数中处理数组
11.处理jni函数中的返回值情况
12.在jni中实现创建java类对象


二、基本步骤:

在介绍这些例子之前,让我们先来看看编写jni方法所需要的基本步骤,这些实例都是用c来实例来讲解,至于c++的实例和c的实例区别不大,只要作稍微的修改即可,在文档的末尾我们将介绍这些内容:

1、要想定义jni方法,首先得要在java语言中对这一方法进行声明(自然这一声明过程要在类中进行)

声明格式如下:

publicnativevoidprint(); System.loadLibrary(“JNIExamples”); }

jni函数用关键字native方法声明。

2、对该类的源文件进行编译使用javac命令,生成相应的.class文件。
3、用javah-jni为函数生成一个在java调用和实际的c函数之间的转换存根,该存根通过从虚拟机栈中取出参数信息,并将其传递给已编译的C函数来实现转换。
4、建立一个特殊的共享库,并从该共享库到处这个存根,在上面的例子中使用了System.loadLibrary,来加载libJNIExamples共享库。


三、配置运行环境:

在编写一个简单的jni函数之前我们必须配置相应的运行环境。jdk的配置在这里就不作介绍,这里主要说的是库的路径。当调用System.loadLibrary(..)时,编译器会到我们系统设置的库路径中寻找该库。修改路径的方法和修改任何环境变量的方法基本相同,只要在/etc/bash.bashrc目录下增加一行LD_LIBRARY_PATH=.:./lib:$(LD_LIBRARY_PATH)即可。也可以通过命令行exportLD_LIBRARY_PATH=.:./lib:$(LD_LIBRARY_PATH)


四、运行实例分析:

1、实例一:在jni中调用标准c中自带的函数printf():

下面以实例1为例来详细说明编写jni方法的详细过程。

(1)、定义包含jni函数的类Print.java:
{ /*********************************************************************** *theprint()functionwillcalltheprintf()funcionwhichisaANSIcfunciton **************************************************************************/publicnativevoidprint(); System.loadLibrary("JNIExamples"); } }


在上面的实例中,使用publicnativevoidprint();语句来定义了一个Print类的jni方法。并用Sysgem.loadLibrary(“JNIExamples”)语句来加载libJNIExamples.so库。注意:加载的语句一定要用static关键字声明在静态块中,以保证引用该类时该库始终被加载。

(2)、对该类进行编译:javacPrint.java。生成Print.class类,然后用javah产生一个Print.h的头文件:javahPrint。长生的Print.h文件格式如下:
/*DONOTEDITTHISFILE-itismachinegenerated*//*HeaderforclassPrint*/JNIEXPORTvoidJNICALLJava_Print_print (JNIEnv*,jobject); }

其中的加粗字体为要实现的JNI函数生命部分。

(3)、编写JNI函数的实现部分Print.c
JNIEXPORTvoidJNICALLJava_Print_print(JNIEnv*env,jobjectobj) { printf("example1:inthisexampleaprintf()functioninANSICiscalled\n"); printf("Hello,theoutputisgeneratedbyprintf()functioninANSIC\n"); }

在这个文件中实现了一个简单的Jni方法。该方法调用ANSIC中的printf()函数,输出了两个句子。

(4)、将本地函数编译到libJNIExamples.so的库中:
使用语句:gcc-fPIC-I/usr/jdk1.5/include-I/usr/jdk1.5/include/linux-shared-olibJNIExamples.soPrint.c。

(5)、至此Jni函数已全部实现,可以在java代码中调用拉。
在此我们使用一个简单的类来对实现的jni方法进行测试,下面是PrintTest.java的源代码部分:
publicstaticvoidmain(String[]args){ Printp=newPrint(); p.print(); } }

(6)、对PrintTest.java进行编译执行得到如下结果:
example1:inthisexampleaprintf()functioninANSICiscalled
Hello,theoutputisgeneratedbyprintf()functioninANSIC.

下面介绍的每个实例实现的步骤也都是按着上述步骤执行的。所以介绍时只介绍实现的关键部分。

2、实例二、调用c 语言用户定义的函数(源程序为:java/Cfunction.java java/C_functionTest.java src/Cfunction.c src/Cfunction.h )
当需要在java程序中调用用c所实现的函数是,需要在需要调用该c函数的类中定义一个jni方法,在该jni方法中去调用该c函数,相当于用java方法把c函数封装起来,以供java程序调用。
在实例二中我们简单定义了一个printHello()函数,该函数的功能只是输出一句话,如果要在java程序中调用该函数,只需在jni函数中调用即可,和调用ANSIC中自带的prinf()函数没有任何区别。

3、实例三、在jni函数中访问java类中的对象实例域(源程序为:java/CommonField.java java/CommonFieldTest.java src/CommonField.c src/CommonField.h )
jni函数的实现部分是在c语言中实现的,如果它想访问java中定义的类对象的实例域需要作三步工作,
(1)调用GetObjectClass()函数得到该对像的类,该函数返回一个jclass类型值。
(2)调用GetFieldID()函数得到要访问的实例域在该类中的id。
(3)调用GetXXXField()来得到要访问的实例域的值。其中XXX和要访问的实例域的类型相对应。
在jni中java编程语言和c语言数据类型的对应关系为java原始数据类型前加'j'表示对应c语言的数据类型例如boolean为jboolean,int为jint,double为jdouble等。对象类型的对应类型为jobject。
在本实例中,您可以看到我们在java/CommonField.java中定义了类CommonField类,其中包含inta,intb两个实例域,我们要在jni函数getCommonField()中对这两个域进行访问和修改。你可以在src/CommonField.c中找到该函数的实现部分。
以下语句是对该域的访问(以下代码摘自:src/CommonField.c):

jclassclass_Field=(*env)->GetObjectClass(env,obj); jfieldIDfdA=(*env)->GetFieldID(env,class_Field,"a","I"); jfieldIDfdB=(*env)->GetFieldID(env,class_Field,"b","I"); jintvalueA=(*env)->GetIntField(env,obj,fdA); jintvalueB=(*env)->GetIntField(env,obj,fdB);


在jni中对所有jni函数的调用都要用到env指针,该指针也是每一个本地方法的第一个参数,他是函数指针表的指针,所以,必须在每一个jni调用前面加上(*env)->GetObjectClass(env,obj)函数调用返回obj对像的类型,其中obj参数表示要你想要得到类型的类对象。
jfieldIDGetFieldID(JNIEnv*env,jclasscl,constcharname[],constcharsig[])该函数返回一个域的标识符name表示域名,sig表示编码的域签名。所谓编码的签名即编码类型的签名在上例中类中的a实例域为int型,用"I”来表示,同理"B”表示byte,"C”表示char,“D”表示double,”F”表示float,“J”表示long,“S”表示short,“V”表示void,”Z”表示boolean类型。
GetIntField(env,obj,fdA),用来访问obj对象的fdA域,如果要访问的域为double类型,则要使用GetDoubleField(env,obj,fdA)来访问,即类型对应GetXXXField中的XXX。

以下函数用来修改域的值:

(*env)->SetIntField(env,obj,fdA,109); (*env)->SetIntField(env,obj,fdB,145);

这和获得域的值类似,只是该函数多了一个要设置给该域的值参数。
访问对象实例域的相关函数如下:
jfieldIDGetFieldID(JNIEnv*env,jclasscl,constcharname[],constcharsig[])
该函数返回一个域的标识符。各参数含义如下:
envJNI接口指针;cl类对象;name域名;sig编码的域签名

XXXGetXXXField(JNIEnv*env,jobjectobj,jfieldIDid)
该函数返回域的值。域类型XXX是Object,Boolean,byte,char,short,int,long,float,double中类型之一。
参数envJNI借口指针;obj为域所在对象;id为域的标识符。
voidSetXXXField(JNIEnv*env,jobjectobj,jfieldIDid,XXXvalue)

该函数用于设置域的值。XXX的含义同上,
参数中env,obj,id的含义也同上,value值为将要设置的值。

4、实例四:在jni函数中访问类的静态实例域 (java/Field.java java/FieldTest.java src/Field.c src/Field.h)

因为静态实例域并不属于某个对象,而是属于一个类,所以在要访问静态实例域时,和访问对象的实例域不同,它所调用的函数是(以实例四来说明,一下代码摘自src/Field.c):
jclassclass_Field=(*env)->FindClass(env,"Field"); jfieldIDfdA=(*env)->GetStaticFieldID(env,class_Field,"a","I"); jintvalueA=(*env)->GetStaticIntField(env,class_Field,fdA); (*env)->SetStaticIntField(env,class_Field,fdA,111);

由于没有对象,必须使用FindClass代替GetObjectClass来获得类引用。在FindClass()的第二个参数是类的编码签名,类的编码签名和基本类型的编码签名有所不同,如果类在当前包中,就直接是类的名称,如果类不在当前包中则要加入该类的详细路径:例如String类在java.lang包中,则String的签名要写成(Ljava/lang/String;),其中的(L和;)是不可少的,其中(;)是表达是的终止符。其他三个函数和访问对象数据域基本没什么区别。

5、实例五:在jni函数中调用java对象的方法(java/CommonMethod.java java/CommonMethodTest.java src/CommonMehod.c src/CommonMethod.h )

在jni函数中我们不仅要对java对象的数据域进行访问,而且有时也需要调用java中类对象已经实现的方法,实例五就是关于这方面的实现的。在src/CommonMethod.c中我们可以找到下面的代码:

JNIEXPORTvoidJNICALLJava_CommonMethod_callMethod (JNIEnv*env,jobjectobj,jinta,jstrings) { printf("example5:inthisexample,aobject'smethodwillbecalled\n"); jclassclass_CommonMethod=(*env)->GetObjectClass(env,obj); jmethodIDmd=(*env)->GetMethodID(env,class_CommonMethod,"print","(ILjava/lang/String;)V"); (*env)->CallVoidMethod(env,obj,md,a,s); }


该代码部分展示了如何实现对java类对象函数的调用过程。从以上代码部分我们可以看到,要实现该调用需要有三个步骤,调用三个函数
jclassclass_CommonMethod=(*env)->GetObjectClass(env,obj); jmethodIDmd=(*env)->GetMethodID(env,class_CommonMethod,"print","(ILjava/lang/String;)V"); (*env)->CallVoidMethod(env,obj,md,a,s);

GetObjectClass(...)函数获得要调用对象的类;GetMethodID(...)获得要调用的方法相对于该类的ID号;CallXXXMethod(...)调用该方法。
在编写该调用过程的时候,需要注意的仍然是GetMethodID(...)函数中编码签名的问题,在该实例中,我们要做的是找到CommonMethod类的print(inta,Strings)方法,该方法打印整数a,和字符串s的直。在函数的编码签名部分(该部分以加粗、并加有下划线)GetMethodID(env,class_CommonMethod,"print","(ILjava/lang/String;)V");从左往右可以查看,括号中的内容为要调用方法的参数部分内容,I表示第一个参数为int类型,“Ljava/lang/String;”表示第二个参数为String类型,V表示返回值类型为空void,如果返回值类型不为空,则使用相应的类型签名。返回值类型是和下面将要使用的调用该方法的函数CallXXXMethod(...)相关联的,该函数的xxx要用相应的类型来替换,在此实例中为void,如果返回值类型为int类型则调用该方法的函数就为CallIntMethod(...)。


6、实例六:在jni函数中调用java类的静态方法(java/Method.java java/MethodTest.java src/Method.h src/Method.c)

实例五中介绍了如何调用类对象的方法,在此实例中我们将介绍如何调用java类的静态方法在此实例中我们在/java/Method.java中定义了静态方法:

publicstaticvoidprint(){
System.out.println("thisisastaticmethodofclassMethod");
}

该函数的功能就是打印字符串“thisisastaticmethodofclassMethod”;
我们在src/Method.c中实现了对该方法调用的jni函数:
JNIEXPORTvoidJNICALLJava_Method_callMethod (JNIEnv*env,jobjectobj) { printf("example6:inthisexample,theclass'sstaticmethodwillbecalled\n"); jclassclass_Method=(*env)->FindClass(env,"Method"); jmethodIDmd=(*env)->GetStaticMethodID(env,class_Method,"print","()V"); (*env)->CallStaticVoidMethod(env,class_Method,md); }


和实例五不同的是,我们要调用的三个函数变为:
FindClass(...)、GetStaticMethodID(...)、CallStaticVoidMethod(...)。
其中的机制和实例五是一样的。再次就不做过多的介绍。

7、实例七:jni函数中传递基本数据类型参数(java/Basic.java java/BasicTest.java src/Basic.c src/Basic.h) 在java/Basic.java中,我们定义了一个public native void raiseValue(int a)函数,该函数将打印使value的值增加a,并打印原来的value和新的value值。
在src/Basic.c中给出了该jni函数的实现部分。
JNIEXPORTvoidJNICALLJava_Basic_raiseValue (JNIEnv*env,jobjectobj,jinta) { printf("example7:inthisexample,aintegertypeparamentwillbepassedtothejnimethod\n"); jclassclass_Basic=(*env)->GetObjectClass(env,obj); jfieldIDfd=(*env)->GetFieldID(env,class_Basic,"value","I"); jintv=(*env)->GetIntField(env,obj,fd); v=v+a; (*env)->SetIntField(env,obj,fd,v); }

在此函数实现中,因为要访问Basic类中的value域,所以调用了GetObjectClass(...),GetFieldID(...),GetIntField(...)函数获取value值,下面一步的“=v+a;”说明,传递基本类型参数的处理方式和在c语言中的基本数据类型的处理无异。


8、实例八:在jni函数中传递对象类型参数(java/Book.java java/BookTest.java src/BookTest.c src/BookTest.h)

在该实例中演示了在jni函数中传递对象函数的过程。

我们在该实例中定义了一个类Book
total_page=t; } publicintgetTotalPage(){ } publicintgetCurrentPage(){ } current_page++; } }

然后我们在java/BookTest.java中定义jni函数
publicnativevoidbookCurrentStatus(Bookb);
该函数需要一个Book类型的参数,并返回该参数的当前状态,包括该书一共有多少页的total_page,以及当前页current_page。函数的实现部分为(src/BookTest.c)
JNIEXPORTvoidJNICALLJava_BookTest_bookCurrentStatus (JNIEnv*env,jobjectthis_obj,jobjectobj) { printf("example8:inthisexample,aobjectparamentwillbepassedtothejnimethod。\n"); jclassclass_book=(*env)->GetObjectClass(env,obj); jmethodIDid_getTotal=(*env)->GetMethodID(env,class_book,"getTotalPage","()I"); jmethodIDid_getCurrent=(*env)->GetMethodID(env,class_book,"getCurrentPage","()I"); jinttotal_page=(*env)->CallIntMethod(env,obj,id_getTotal); jintcurrent_page=(*env)->CallIntMethod(env,obj,id_getCurrent); printf("thetotalpageis:%dandthecurrentpageis:%d\n",total_page,current_page); }

该函数包含三个参数(JNIEnv*env,jobjectthis_obj,jobjectobj),第二个jobjectthis_obj参数表示当前的jni函数所属于的类对象,第三个jobjectobj参数表示传递的参数Book类型的类对象。
对于实现部分,基本和实例五--调用java类对象的方法中的操作相同,就不作详解。

9、实例九:在jni函数中处理字符串(java/Str.java java/StrTest.java src/Str.c src/Str.h)
在该实例中我们讲解如何传递、处理字符串参数。
在java/Str.java中我们定义了一个printString(Strings)的方法,用来处理字符串参数。
在src/Str.c中我们可以看到该函数的实现部分:
JNIEXPORTvoidJNICALLJava_Str_printString (JNIEnv*env,jobjectobj,jstrings) { printf("example9:inthisexample,aStringobjectparamentwillbepassedtothejnimethod.\n"); string=(char*)(*env)->GetStringUTFChars(env,s,NULL); printf("%sisputoutinnativemethod\n",string); (*env)->ReleaseStringUTFChars(env,s,(jbyte*)string); }

实现过程中调用了两个函数:GetStringUTFChars(...)、ReleaseStringUTFChars(...)。
GetStringUTFChars(...)用来获取String对象的字符串,并将其抓那还为char*类型,这应该字符串就可以在c语言中进行处理拉。ReleaseStringUTFChars(...)用于当该字符串使用完成后,将其进行垃圾回收。记住,当使用完字符串时一定不要忘记调用该函数。

10、实例十:在jni函数中处理数组(java/Arr.java java/ArrTest.java src/Arr.c src/Arr.h)
java中所有的数组类型都有相对应的c语言类型,其中jarray类型表示一个泛型数组
boolean[]--jbooleanArraybyte[]--jbyteArraychar[]--jcharArary
int[]---jcharArrayshort[]---jshortArraylong[]---jlongArrayfloat[]--jfloatArray
double[]—-jdoubleArrayObject[]---jobjectArray。当访问数组时,可以通过GetObjectAraryElement和SetObjectArrayElement方法访问对象数组的元素。
而对于一般类型数组,你可以调用GetXXXAraryElements来获取一个只想数组起始元素的指针,而当你不在使用该数组时,要记得调用ReleaseXXXArrayElements,这样你所作的改变才能保证在原始数组里得到反映。当然如果你需要得到数组的长度,可以调用GetArrayLength函数。
在本实例中,我们在Arr.java中定义一个本地方法:print(intintArry[]),该函数的功能为对该数组进行输出,在src/Arr.c中我们可以看到该方法的实现过程如下:
JNIEXPORTvoidJNICALLJava_Arr_print (JNIEnv*env,jobjectobj,jintArrayintArray) { printf("example10:inthisexample,aarrayparamentwillbepassedtothejnimethod.\n"); arr=(*env)->GetIntArrayElements(env,intArray,NULL); //n=(*env)->GetArrayLength(env,intArray); printf("thenativemethodoutputtheintarray\n"); for(i=0;i<(*env)->GetArrayLength(env,intArray);i++) { printf("%d",arr[i]); } (*env)->ReleaseIntArrayElements(env,intArray,arr,0); }

我们在此调用了GetIntArrayElements(...)来获取一个指向intArray[]数组第一个元素的指针。
用getArrayLength(..)函数来得到数组的长度,以方便数组遍历时使用。最后应用ReleaseArrayElements(...)函数来释放该数组指针。

11、实例十一:在jni中的返回值问题(java/ReturnValue.java java/ReturnValueTest.java java/BookClass.java src/ReturnValue.c src/ReturnValue.h)
在java/ReturnValue类中定义了三个jni方法:returnInt(),returnString(),returnObject()
三个方法,分别返回int,String,Object类型的值。
其在src/ReturnValue.c中的实现分别为:

JNIEXPORTjintJNICALLJava_ReturnValue_returnInt (JNIEnv*env,jobjectobj) { jclassclass_ReturnValue=(*env)->GetObjectClass(env,obj); jfieldIDfd=(*env)->GetFieldID(env,class_ReturnValue,"value","I"); jintv=(*env)->GetIntField(env,obj,fd); } *Signature:()Ljava/lang/String; JNIEXPORTjstringJNICALLJava_ReturnValue_returnString (JNIEnv*env,jobjectobj) { printf("example11:inthisexample,theintandobjectofreturnvaluewillbeproceeding\n"); jclassclass_ReturnValue=(*env)->GetObjectClass(env,obj); jfieldIDfd=(*env)->GetFieldID(env,class_ReturnValue,"name","Ljava/lang/String;"); jstringjstr=(jstring)(*env)->GetObjectField(env,obj,fd); } **Method:returnObject JNIEXPORTjobjectJNICALLJava_ReturnValue_returnObject (JNIEnv*env,jobjectobj) { jclassclass_ReturnValue=(*env)->GetObjectClass(env,obj); jfieldIDfd=(*env)->GetFieldID(env,class_ReturnValue,"myBook","LBookClass;"); jobjectjbook=(jstring)(*env)->GetObjectField(env,obj,fd); }

在这里分别涉及到了对java类对象的一般参数,String参数,以及Object参数的访问。


12、实例十二:在jni中创建java类对象:(java/Test.java src/CreateObj.c src/CreateObj.h)

如果想要在jni函数创建java类对象则要引用java类的构造器方法,通过调用NewObject函数来实现。
NewObject函数的调用方式为:
jobjectobj_new=(*env)->NewObject(env,class,methodid,paraments);
在该实例中,我们在java/Test.java中定义了Book1类,要在CreateObj类的modifyProperty()jni方法中创建该类对象。我们可以在src/CreateObj.c中看到该jni方法创建对象的过程:
jobjectbook; jclassclass_book; jmethodIDmd_book; class_book=(*env)->FindClass(env,"LBook1;"); md_book=(*env)->GetMethodID(env,class_book,"<init>","(IILjava/lang/String;)V"); book=(*env)->NewObject(env,class_book,md_book,100,1,"huanghe");


在创建对象的过程中可以看到,要创建一个java类对象,首先需要得到得到使用FindClass函数得到该类,然后使用GetMethodID方法得到该类的构造器方法id,主义在此时构造器的函数名始终为:"”,其后函数的签名要符合函数签名规则。在此我们的构造器有三个参数:int,int,String.
并且其返回值类型要永久为空,所以函数签名为:"(IILjava/lang/String;)V"
然后我们调用NewObject()函数来创建该类的对象,在此之后就可以使用该对象拉。

以上内容介绍的是jni函数c语言的实现实例。如果想要使用c++的实例,我们只需要把其中的每一个函数调用过程作稍微的修改:
例如:(*env)->NewObject(env,class_book,md_book,100,1,”huanghe”);
修改为:(env)->NewObject(class_book,md_book,100,1,”huanghe”);
即修改(*env)为(env)再把参数中的env去掉。然后把所有c的函数改为c++的函数就OK拉。
具体情况可以去查看我们的c++实例代码.

分享到:
评论

相关推荐

    JNI完全技术手册 带完整书签

    Chap9:如何编写jni方法(转载)... 55 1、实例一:在jni中调用标准c中自带的函数printf(): 57 2、实例二、调用c 语言用户定义的函数... 58 3、实例三、在jni函数中访问java类中的对象实例域... 58 4、实例四:在...

    JNI调用大全

    Chap1:JNI完全手册... 3 Chap2:JNI-百度百科... 11 Chap 3:javah命令帮助信息......Chap 4:用javah产生一个.h文件......Chap5:jni教程(very very good) 19 Chap6: JNI传递返回值......Chap9:如何编写jni方法(转载)... 55

    JNI学习示例代码,含java代码工程和win32 dll工程

    JNI,全称为Java Native Interface,即Java本地接口,JNI是Java调用Native 语言的一种特性。通过JNI可以使得Java与C/C++机型交互。即可以在Java代码中调用C/C++等语言的代码或者在C/C++代码中调用Java代码。由于JNI...

    JNI文档资料源码_2020_01_22

    【Android NDK 开发】Visual Studio 2019 使用 CMake 开发 JNI 动态库 ( 动态库编译配置 | JNI 头文件导入 | JNI 方法命名规范 ) 博客地址 : https://hanshuliang.blog.csdn.net/article/details/104068609 博客...

    使用JNI调用本地接口(解决中文字符传递,源码+说明)

    通过JNI调用本地DLL,并传递中文字符串, Visual C++ 6.0 开发DLL 原创作品,随意转载,提前请说明!

    JNA—JNI终结者(转载)

    NULL 博文链接:https://8366.iteye.com/blog/1100396

    JNI文档资料源码_2020_02_04.zip

    【Android NDK 开发】JNI 方法解析 ( C/C++ 调用 Java 方法 | 函数签名 | 调用对象方法 | 调用静态方法 ) I . 调用 Java 方法流程 II . 获取 jclass 对象 ( GetObjectClass ) III . 获取 jclass 对象 ( Find...

    使用JNI调用本地接口(解决中文问题)

    使用JNI与本地接口,并传递中文字符串。 绝对原创,转载请说明!

    android jni开发实例

    转载几篇介绍android jni开发方法的文章,有介绍基础的,有介绍方法的,也有实例可参考。

    jna-3.5.2jar

    JNA的功能和P/Invoke类似,但编写方法与P/Invoke截然不同。JNA没有使用Annotation, 而是通过编写一般的Java代码来实现。 P/Invoke是.NET平台的机制。而JNA是Java平台上的一个开源类库,和其他类库没有 什么区别。只...

    jdbc连接数据库的方式2

    我建议用户认真学习如何最大限度地发挥SQL的功能。 1、查找驱动程序 MySQL目前提供的java驱动程序为Connection/J,可以从MySQL官方网站下载,并找到mysql-connector-java-3.0.15-ga-bin.jar文件,此驱动程序为纯...

    尼斯知识体系:不积跬步无以至千里,每天进步一点点,激情,自我调节,爱与分享

    知识体系总结 如果你感到委屈,证明你还有底线;如果你感到迷茫,证明你还有追求;如果你感到痛苦,证明你还有力气;...NDK JNI学习 文章标题 状态 原创,转载 已发布 原创 已发布 原创 自定义视图 文章标题 状态 原创

    JAVA调用C语言写的SO文件

    因为工作需要写一份SO文件,作为手机硬件IC读卡和APK交互的桥梁,也是中间件,看了网上有说到JNI接口技术实现,这里转载了一个实例 1 // 用JNI实现 2 // 实例: 3 4 // 创建HelloWorld.java 5 class HelloWorld...

Global site tag (gtag.js) - Google Analytics