- 浏览: 479489 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
alvin198761:
renzhengzhi 写道我参与过12306余票查询系统的开 ...
别给12306 辩解了 -
renzhengzhi:
我参与过12306余票查询系统的开发,用户请求被前面3层缓存拦 ...
别给12306 辩解了 -
renzhengzhi:
写的很好。
JAVA线程dump的分析 -
liyonghui160com:
说好的附件呢
分布式服务框架 Zookeeper -- 管理分布式环境中的数据 -
ghpaas:
orbeon作为xforms标准的实现,不论其设计器还是运行时 ...
XForms 1.1 中文翻译—第1章 关于XForms标准
15.2 调用C程序
JNI规范最初便是针对Java调用C语言的,因此对C程序的调用具有一套约定俗成的步骤: (1)编写作为主调方的Java类。Java类一方面声明将要调用的C函数,一方面载入本地的动态链接库文件(即.dll文件)。 (2)使用javac命令编译Java类。 (3)使用javah命令为C程序生成头文件(即.h文件)。在自动生成的头文件中将声明有待实现的C函数。 (4)编写C程序。在C程序中实现头文件中声明的函数。 (5)将C程序文件编译成动态链接库文件。任何C编译工具都能用来完成此项工作,如Windows平台的VC++和BCB、Linux平台的gcc、Solaris平台的cc。 本章选择Windows平台作为实战JNI的第一站,本节我们将在Windows平台上完整地实现一个最简单的Java程序调用C函数的范例。使用的C程序编译工具是VC++;为了方便读者们理解,本节内容在编排上严格按照上述的开发步骤进行。 我们仍然以著名的“Hello World”为例,所不同之处在于,这次发出问候语的是动态链接库中的C函数,而非Java程序本身,Java程序仅仅负责调用C函数而已。 作为主调方的Java程序源代码如下。 代码清单15-1 在Windows平台上调用C函数的例程——HelloWorld 1. public class HelloWorld 2. { 3. public native void displayHelloWorld();//定义本地方法 4. public native void displayMyName();//定义本地方法 5. 6. static 7. { 8. System.loadLibrary("hello");//调入本地库 9. } 10. 11. public static void main(String[] args) 12. { 13. new HelloWorld().displayHelloWorld(); 14. new HelloWorld().displayMyName(); 15. } 16. } 观察这段Java程序,在结构上与普通的Java程序的不同之处在于,它首先声明了两个native方法——与在Interface中的声明方法很类似,但是两者却有本质的区别:Interface中声明的只是方法的结构而已,可以认为是对方法做出的定义,Interface自身并不实现方法,更没有能力提供方法;而native方法却可以认为是Class自身提供的方法,只不过这种方法不是由自身来实现的,而是依靠本地动态链接库输出的函数。 在接下来的部分是一段静态(static)代码,载入动态链接库,之前声明的native方法就将在载入的动态链接库中寻找。如果native方法分散在多个动态链接库中,则需要载入多个动态链接库。本例程载入的动态链接库命名为“hello”,这意味着在Windows平台上,Java程序将在java.library.path参数所指向的路径,以及PATH环境变量所指向的路径中寻找并载入hello.dll文件。 抛开本地方法如何实现不说,我们可以看到在main()方法中,调用native方法和调用普通方法是完全相同的。 使用JDK提供的命令行编译HelloWord类、为准备提供函数的(尚未实现的)C程序生成头文件的命令行如下: javac HelloWorld.java javah HelloWorld 读者们不妨打开生成的头文件HelloWorld.h阅读,但是请不要修改。 代码清单15-2 在Windows平台上调用C函数的例程——HelloWorld.h 1. /* DO NOT EDIT THIS FILE - it is machine generated */ 2. #include <jni.h> 3. /* Header for class HelloWorld */ 4. 5. #ifndef _Included_HelloWorld 6. #define _Included_HelloWorld 7. #ifdef __cplusplus 8. extern "C" { 9. #endif 10. /* 11. * Class: HelloWorld 12. * Method: displayHelloWorld 13. * Signature: ()V 14. */ 15. JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld 16. (JNIEnv *, jobject); 17. 18. /* 19. * Class: HelloWorld 20. * Method: displayMyName 21. * Signature: ()V 22. */ 23. JNIEXPORT void JNICALL Java_HelloWorld_displayMyName 24. (JNIEnv *, jobject); 25. 26. #ifdef __cplusplus 27. } 28. #endif 29. #endif 头文件定义了两个函数:Java_HelloWorld_displayHelloWorld()和Java_HelloWorld_ displayMyName()。javah工具在生成的头文件中,在方法名前面加上了“Java_类名”。另外请注意,JNI规范中为所有的函数均加上了两个参数:一个是指向JNIEnv类型的指针,另一个是jobject类型的变量。JNIEnv和jobject类型都是在jni.h中定义的,jni.h由各个平台的JDK自带(存在于JDK\include目录下)。本例程没有使用到这两个参数,更复杂的程序将涉及它们,我们放在下一节介绍。 以上结论同样适用于本章后面将要介绍的“调用Delphi程序”的相关内容。 按照既定的步骤,接下来我们要编写C程序来实现这两个函数了。源代码如下。 代码清单15-3 在Windows平台上调用C函数的例程——hello.c 1. #include <stdio.h> 2. #include <jni.h> 3. #include <HelloWorld.h> 4. 5. JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld(JNIEnv *env, jobject obj) 6. { 7. printf("Hello world!\n"); 8. return; 9. } 10. 11. JNIEXPORT void JNICALL Java_HelloWorld_displayMyName(JNIEnv *env, jobject obj) 12. { 13. printf("我叫XXX!\n"); 14. return; 15. } 负责实现输出函数的hello.c首先引入了两个头文件,一个是JDK自带的jni.h,另一个则是使用javah工具产生的HelloWorld.h。 在Windows平台上可以选用VC++编译hello.c,从而产生最终需要的hello.dll动态链接库文件,在编译过程中需要引入jni.h等JDK为Windows平台提供的头文件。编译命令行如下: cl -If:\jdk\include -If:\jdk\include\win32 -LD hello.c -Fehello.dll 命令行中的cl.exe是VC++提供的编译工具,存在于VC++\bin目录下。涉及的命令选项说明如下。 — -I:指引入(Include)必要的头文件所在的路径。请读者们根据自己机器上JDK安装的路径自行调整路径;如果HelloWorld.h不在当前目录下,也请通过“-I”选项予以引入。 — -LD:指载入(Load)源文件。 — -Fe:编译后输出的文件。 如果一切无误的话,在当前目录下将产生hello.dll动态链接库文件。通过以下命令行执行Java程序: java HelloWorld 如果执行过程中发生如下异常: Exception in thread "main" java.lang.UnsatisfiedLinkError: no hello in java.library.path at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1410) at java.lang.Runtime.loadLibrary0(Runtime.java:772) at java.lang.System.loadLibrary(System.java:832) 则意味着hello.dll无法被载入,可以通过以下三种途径解决这个问题: — 将hello.dll放置在当前目录下。 — 将hello.dll放置在PATH环境变量所指向的路径下。 — 启动JVM时指定选项“-Djava.library.path”,将hello.dll放置在该选项所指向的路径下。 在Linux环境下,我们首先要通过某种编辑器编辑程序的源文件,比如常用的VIM和EMACS。如果要编译一个C语言源程序,我们可以使用GNU的gcc(GNU Compiler Collection)编译器。假设我们有一个非常简单的源程序hello.c,要编译这个程序,我们只要在命令行下执行: gcc -o hello hello.c gcc编译器就会为我们生成一个名为hello的可执行文件。执行“./hello”就可以看到程序的输出结果了。命令行中的“-o”选项表示我们要求编译器将我们输出的可执行文件命名为hello,而hello.c 是我们的源程序文件。 gcc编译器有许多选项,一般来说我们只要知道其中的几个常用的就够了: — -o选项如上所述,表示要求输出的可执行文件名。 — -c选项表示只要求编译器输出目标代码,而不必要输出可执行文件。 — -g选项表示要求编译器在编译的时候提供对程序进行调试的信息。 假设有一套程序共由5个文件组成:main.c、too11.h、tool1.c、tool2.h和tool2.c。其中tool1.c和tool2.c是供main.c调用的工具程序,它们所包含的函数分别在tool1.h和tool2.h中定义。则编译的过程如下: gcc -c main.c #编译产生main.o目标文件 gcc -c tool1.c #编译产生tool1.o目标文件 gcc -c tool2.c #编译产生tool2.o目标文件 gcc -o main main.o tool1.o tool2.o #将三个目标文件连接成可执行文件main 如果源文件数量多的话,在修改调试过程中难免重复执行上述步骤,这样耗时耗力。解决办法是引入Makefile文件。Makefile文件是编译规则的配置文件,它的一般格式是: 目标:依赖文件列表 规则列表 第1行是声明目标(可能是可执行文件或者目标文件)所依赖的文件(可能是源文件或者目标文件)列表;第2行规定的是第1行中的依赖文件中的任何一个发生变化后需要执行的编译动作。就上面的例子来说,可能的Makefile文件是: main:main.o tool1.o tool2.o gcc -o main main.o tool1.o tool2.o main.o:main.c tool1.h tool2.h gcc -c main.c tool1.o:tool1.c tool1.h gcc -c tool1.c tool2.o:tool2.c tool2.h gcc -c tool2.c 当引入Makefile文件之后,即使源文件数量多也不用执行过多的命令行,而只需输入一个命令即可通知gcc依据Makefile文件所规定的依赖关系自动发现需要重新编译的文件: make 本节的例程和第15.2.1节的例程复杂程度相当,只是切换到了Linux平台上,目的是为了帮助读者们熟悉Linux下的Java+C开发环境。 作为主调方的Java源程序TestJNI.java如下。 代码清单15-4 在Linux平台上调用C函数的例程——TestJNI.java 1. public class TestJNI 2. { 3. static 4. { 5. System.loadLibrary("testjni");//载入静态库,test函数在其中实现 6. } 7. 8. private native void testjni(); //声明本地调用 9. 10. public void test() 11. { 12. testjni(); 13. } 14. 15. public static void main(String args[]) 16. { 17. TestJNI haha = new TestJNI(); 18. haha.test(); 19. } 20. } TestJNI.java声明从libtestjni.so(注意Linux平台的动态链接库文件的扩展名是.so)中调用函数testjni()。 编译TestJNI.java,并为C程序生成头文件: java TestJNI.java javah TestJNI 提供testjni()函数的testjni.c源文件如下。 代码清单15-5 在Linux平台上调用C函数的例程——testjni.c 1. #include <stdio.h> 2. #include <TestJNI.h> 3. 4. JNIEXPORT void JNICALL Java_TestJNI_testjni(JNIEnv *env, jobject obj) 5. { 6. printf("haha---------go into c!!!\n"); 7. } 编写Makefile文件如下,JDK安装的位置请读者自行调整: libtestjni.so:testjni.o gcc -rdynamic -shared -o libtestjni.so testjni.o testjni.o:testjni.c TestJNI.h gcc -c testjni.c -I./ -I/usr/java/jdk1.6.0_00/include -I/usr/java/jdk1.6.0_00/include/linux 在Makefile文件中,我们描述了最终的libtestjin.so依赖于目标文件testjni.o,而testjni.o则依赖于testjni.c源文件和TestJNI.h头文件。请注意,我们在将testjni.o连接成动态链接库文件时使用了“-rdynamic”选项。 执行make命令编译testjni.c。Linux平台和在Windows平台上类似,有3种方法可以让Java程序找到并装载动态链接库文件。 — 将动态链接库文件放置在当前路径下。 — 将动态链接库文件放置在LD_LIBRARY_PATH环境变量所指向的路径下。注意这一点和Windows平台稍有区别,Windows平台参考PATH环境变量。 — 在启动JVM时指定选项“-Djava.library.path”,将动态链接库文件放置在该选项所指向的路径下。 从下一节开始,我们开始接触到在JNI框架内Java调用C程序的一些高级话题,包括如何传递参数、如何传递数组、如何传递对象等。 各种类型数据的传递是跨平台、跨语言互操作的永恒话题,更复杂的操作其实都可以分解为各种基本数据类型的操作。只有掌握了基于各种数据类型的互操作,才能称得上掌握了JNI开发。从下一节开始,环境和步骤不再是阐述的重点,将不再花费专门的篇幅,例程中的关键点将成为我们关注的焦点。 到目前为止,我们还没有实现Java程序向C程序传递参数,或者C程序向Java程序传递参数。本例程将由Java程序向C程序传入一个字符串,C程序对该字符串转成大写形式后回传给Java程序。 Java源程序如下。 代码清单15-6 在Linux平台上调用C函数的例程——Sample1 1. public class Sample1 2. { 3. public native String stringMethod(String text); 4. 5. public static void main(String[] args) 6. { 7. System.loadLibrary("Sample1"); 8. Sample1 sample = new Sample1(); 9. String text = sample.stringMethod("Thinking In Java"); 10. System.out.println("stringMethod: " + text); 11. } 12. } Sample1.java以“Thinking In Java”为参数调用libSample1.so中的函数stringMethod(),在得到返回的字符串后打印输出。 Sample1.c的源程序如下。 代码清单15-7 在Linux平台上调用C函数的例程——Sample1.c 1. #include <Sample1.h> 2. #include <string.h> 3. 4. JNIEXPORT jstring JNICALL Java_Sample1_stringMethod(JNIEnv *env, jobject obj, jstring string) 5. { 6. const char *str = (*env)->GetStringUTFChars(env, string, 0); 7. char cap[128]; 8. strcpy(cap, str); 9. (*env)->ReleaseStringUTFChars(env, string, str); 10. int i=0; 11. for(i=0;i<strlen(cap);i++) 12. *(cap+i)=(char)toupper(*(cap+i)); 13. return (*env)->NewStringUTF(env, cap); 14. } 首先请注意函数头部分,函数接收一个jstring类型的输入参数,并输出一个jstring类型的参数。jstring是jni.h中定义的数据类型,是JNI框架内特有的字符串类型,因为jni.h在Sample1.h中被引入,因此在Sample1.c中无须再次引入。 程序的第4行是从JNI调用上下文中获取UTF编码的输入字符,将其放在指针str所指向的一段内存中。第9行是释放这段内存。第13行是将经过大写转换的字符串予以返回,这一句使用了NewStringUTF()函数,将C语言的字符串指针转换为JNI的jstring类型。JNIEnv也是在jni.h中定义的,代表JNI调用的上下文,GetStringUTFChars()、ReleaseStringUTFChars()和NewStringUTF()均是JNIEnv的函数。 本节例程将首次尝试在JNI框架内启用数组:C程序向Java程序返回一个定长的整型数组成的数组,Java程序将该数组打印输出。 Java程序的源代码如下。 代码清单15-8 在Linux平台上调用C函数的例程——Sample2 1. public class Sample2 2. { 3. public native int[] intMethod(); 4. 5. public static void main(String[] args) 6. { 7. System.loadLibrary("Sample2"); 8. Sample2 sample=new Sample2(); 9. int[] nums=sample.intMethod(); 10. for(int i=0;i<nums.length;i++) 11. System.out.println(nums[i]); 12. } 13. } Sample2.java调用libSample2.so中的函数intMethod()。Sample2.c的源代码如下。 代码清单15-9 在Linux平台上调用C函数的例程——Sample2.c 1. #include <Sample2.h> 2. 3. JNIEXPORT jintArray JNICALL Java_Sample2_intMethod(JNIEnv *env, jobject obj) 4. { 5. inti = 1; 6. jintArray array;//定义数组对象 7. array = (*env)-> NewIntArray(env, 10); 8. for(; i<= 10; i++) 9. (*env)->SetIntArrayRegion(env, array, i-1, 1, &i); 10. 11. /* 获取数组对象的元素个数 */ 12. int len = (*env)->GetArrayLength(env, array); 13. /* 获取数组中的所有元素 */ 14. jint* elems = (*env)-> GetIntArrayElements(env, array, 0); 15. for(i=0; i<len; i++) 16. printf("ELEMENT %d IS %d\n", i, elems[i]); 17. 18. return array; 19. } Sample2.c涉及了两个jni.h定义的整型数相关的数据类型:jint和jintArray,jint是在JNI框架内特有的整数类型。程序的第7行开辟出一个长度为10 的jint数组。然后依次向该数组中放入元素1-10。第11行至第16行不是程序的必须部分,纯粹是为了向读者们演示GetArrayLength()和GetIntArrayElements()这两个函数的使用方法,前者是获取数组长度,后者则是获取数组的首地址以便于遍历数组。 本节例程是对上节例程的进一步深化:虽然仍然是传递数组,但是数组的基类换成了字符串这样一种对象数据类型。Java程序将向C程序传入一个包含中文字符的字符串,C程序并没有处理这个字符串,而是开辟出一个新的字符串数组返回给Java程序,其中还包含两个汉字字符串。 Java程序的源代码如下。 代码清单15-10 在Linux平台上调用C函数的例程——Sample3 1. public class Sample3 2. { 3. public native String[] stringMethod(String text); 4. 5. public static void main(String[] args) throws java.io.UnsupportedEncodingException 6. { 7. System.loadLibrary("Sample3"); 8. Sample3 sample = new Sample3(); 9. String[] texts = sample.stringMethod("java编程思想"); 10. for(int i=0;i<texts.length;i++) 11. { 12. texts[i]=new String(texts[i].getBytes("ISO8859-1"),"GBK"); 13. System.out.print( texts[i] ); 14. } 15. System.out.println(); 16. } 17. } Sample3.java调用libSample3.so中的函数stringMethod()。Sample3.c的源代码如下: 代码清单15-11 在Linux平台上调用C函数的例程——Sample3.c 1. #include <Sample3.h> 2. #include <string.h> 3. #include <stdlib.h> 4. 5. #define ARRAY_LENGTH 5 6. 7. JNIEXPORT jobjectArray JNICALL Java_Sample3_stringMethod(JNIEnv *env, jobject obj, jstring string) 8. { 9. jclass objClass = (*env)->FindClass(env, "java/lang/String"); 10. jobjectArray texts= (*env)->NewObjectArray(env, (jsize)ARRAY_LENGTH, objClass, 0); 11. 12. jstring jstr; 13. char* sa[] = { "Hello,", "world!", "JNI", "很", "好玩" }; 14. int i=0; 15. for(;i<ARRAY_LENGTH;i++) 16. { 17. jstr = (*env)->NewStringUTF( env, sa[i] ); 18. (*env)->SetObjectArrayElement(env, texts, i, jstr);//必须放入jstring 19. } 20. 21. return texts; 22. } 第9、10行是我们需要特别关注的地方:JNI框架并没有定义专门的字符串数组,而是使用jobjectArray——对象数组,对象数组的基类是jclass,jclass是JNI框架内特有的类型,相当于Java语言中的Class类型。在本例程中,通过FindClass()函数在JNI上下文中获取到java.lang.String的类型(Class),并将其赋予jclass变量。 在例程中我们定义了一个长度为5的对象数组texts,并在程序的第18行向其中循环放入预先定义好的sa数组中的字符串,当然前置条件是使用NewStringUTF()函数将C语言的字符串转换为jstring类型。 本例程的另一个关注点是C程序向Java程序传递的中文字符,在Java程序中能否正常显示的问题。在笔者的试验环境中,Sample3.c是在Linux平台上编辑的,其中的中文字符则是用支持GBK的输入法输入的,而Java程序采用ISO8859_1字符集存放JNI调用的返回字符,因此在“代码清单15-10在Linux平台上调用C函数的例程——Sample3”的第14行中将其转码后输出。 本节例程演示的是C程序向Java程序传递对象数组,而且对象数组中存放的不再是字符串,而是一个在Java中自定义的、含有一个topic属性的MailInfo对象类型。 MailInfo对象定义如下。 代码清单15-12 在Linux平台上调用C函数的例程——MailInfo 1. public class MailInfo 2. { 3. public String topic; 4. 5. public String getTopic() 6. { 7. return this.topic; 8. } 9. 10. public void setTopic(String topic) 11. { 12. this.topic=topic; 13. } 14. } Java程序的源代码如下。 代码清单15-13 在Linux平台上调用C函数的例程——Sample4 1. public class Sample4 2. { 3. public native MailInfo[] objectMethod(String text); 4. 5. public static void main(String[] args) 6. { 7. System.loadLibrary("Sample4"); 8. Sample4 sample = new Sample4(); 9. MailInfo[] mails = sample.objectMethod("Thinking In Java"); 10. for(int i=0;i<mails.length;i++) 11. System.out.println(mails[i].topic); 12. } 13. } Sample4.java调用libSample4.so中的objectMethod()函数。Sample4.c的源代码如下。 代码清单15-14 在Linux平台上调用C函数的例程——Sample4.c 1. #include <Sample4.h> 2. #include <string.h> 3. #include <stdlib.h> 4. 5. #define ARRAY_LENGTH 5 6. 7. JNIEXPORT jobjectArray JNICALL Java_Sample4_objectMethod(JNIEnv *env, jobject obj, jstring string) 8. { 9. jclass objClass = (*env)->FindClass(env, "java/lang/Object"); 10. jobjectArray mails= (*env)->NewObjectArray(env, (jsize)ARRAY_LENGTH, objClass, 0); 11. 12. jclass objectClass = (*env)->FindClass(env, "MailInfo"); 13. jfieldID topicFieldId = (*env)->GetFieldID(env, objectClass, "topic", "Ljava/lang/String;"); 14. 15. int i=0; 16. for(;i<ARRAY_LENGTH;i++) 17. { 18. (*env)->SetObjectField(env, obj, topicFieldId, string); 19. (*env)->SetObjectArrayElement(env, mails, i, obj); 20. } 21. 22. return mails; 23. } 程序的第9、10行读者们应该不会陌生,在上一节的例程中已经出现过,不同之处在于这次通过FindClass()函数在JNI上下文中获取的是java.lang.Object的类型(Class),并将其作为基类开辟出一个长度为5的对象数组,准备用来存放MailInfo对象。 程序的第12、13行的目的则是创建一个jfieldID类型的变量,在JNI中,操作对象属性都是通过jfieldID进行的。第12行首先查找得到MailInfo的类型(Class),然后基于这个jclass进一步获取其名为topic的属性,并将其赋予jfieldID变量。 程序的第18、19行的目的是循环向对象数组中放入jobject对象。SetObjectField()函数属于首次使用,该函数的作用是向jobject的属性赋值,而值的内容正是Java程序传入的jstring变量值。请注意在向对象属性赋值和向对象数组中放入对象的过程中,我们使用了在函数头部分定义的jobject类型的环境参数obj作为中介。至此,JNI框架固有的两个环境入参env和obj,我们都有涉及。15.2.1 在Windows平台上调用C函数
15.2.2 在Linux平台上调用C函数
15.2.2.1 gcc简介
15.2.2.2 简单例程
15.2.2.3 传递字符串
15.2.2.4 传递整型数组
15.2.2.5 传递字符串数组
15.2.2.6 传递对象数组
发表评论
-
.NET开源核心运行时,且行且珍惜
2014-12-25 15:39 1859背景 2014年11月12日,ASP.NET之父、微软云 ... -
常用 Java Profiling 工具的分析与比较
2010-08-15 22:04 1180相对于静态代码分析,Profiling 是通过收集程序运行 ... -
监控系统内存
2010-07-01 14:15 1214public CollectorThread(int seco ... -
Debugging the JNI
2010-06-18 14:03 996If you think you have a JNI p ... -
JNI原理1
2010-06-18 13:14 1260在某些Java的忠实支持者眼中,JNI(Java Nati ... -
JNI的crash终于搞定<转>
2010-06-18 13:08 1677今天终于搞定困扰我一周的一个问题了。我们的算法通过jni封装, ... -
java的volatile是什么意思
2010-04-20 15:39 1334我们知道,在Java中设置变量值的操作,除了long和d ... -
Concurrent kickoff
2010-04-19 15:55 1384This example shows you the ... -
IBM JDK和sun jdk区别
2010-04-19 15:52 2578在IBM的虚拟机官方指导文档中明确指出,禁止将虚拟机的最大 ... -
如何在IBM JDK 1.4.2的环境中避免Java堆空间的碎片问题
2010-04-19 15:48 875用户在使用WebSphere Applic ... -
Concurrent mark
2010-04-15 19:39 1016Concurrent mark gives reduced ... -
Java 技术,IBM 风格: 垃圾收集策略,第 1 部分
2010-04-15 16:51 985可以使用 4 种不同的策略配置 IBM Developer ... -
Java 网页浏览器组件介绍
2010-04-12 23:44 1503前言 在使用 Java 开发客户端程序时,有时会需要在界 ... -
利用 Java dump 进行 JVM 故障诊断
2010-04-06 16:54 1966引言 对于大型 java 应用程序来说,再精细的测试都难 ... -
IBM JVM垃圾回收原理——1
2010-04-06 15:42 1616原文下载:IBM Garbage Collection ... -
Java 理论与实践: 垃圾收集简史
2010-04-06 14:34 818垃圾收集的好处是无 ... -
关注性能: 调优垃圾收集
2010-04-06 14:08 828随着网志作为公共日 ... -
Java 理论与实践: JVM 1.4.1 中的垃圾收集
2010-04-06 10:42 886老对象和年轻对象 ... -
优化 Java 垃圾收集器改进系统性能
2010-04-02 16:05 902From http://www.ibm.com/de ... -
搞懂java中的synchronized关键字
2010-04-01 19:54 812实际上,我关于java的基 ...
相关推荐
要深入理解JNI的实现原理,本书《JNI实现原理权威指南》无疑是提供了一个全面的技术指导和规范说明。 ### 知识点一:JNI的概念及其重要性 JNI是Java平台标准版的一部分,它为Java代码和本地应用程序接口(API)...
在Android系统中,JNI(Java Native Interface)是一种技术,它允许Java代码和其他语言写的代码进行交互。...通过研究这个项目,开发者可以深入理解JNI的工作原理,以及如何在Android系统下有效地进行I2C通信。
**JNI原理** JNI的核心在于创建一个桥接,允许Java代码与本地代码交互。当Java虚拟机(JVM)遇到一个声明为`native`的方法时,它不会尝试解释执行该方法,而是通过JNI接口寻找对应的本地实现。这个本地实现通常是一...
同时,由于涉及到跨语言和跨平台,理解JNI的工作原理和正确使用JNI头文件至关重要,这样才能确保Java和本地代码之间的无缝交互。 在提供的压缩包`jni.zip`中,包括了`jni.h`和`jni_md.h`两个头文件,它们是进行JNI...
2. **JNI工作原理** JNI的核心是Java虚拟机(JVM)和本地方法库(Native Method Library)之间的桥梁。Java代码通过`System.loadLibrary`加载动态链接库(DLL或SO文件),然后使用`native`关键字声明的函数来调用...
JNI,全称Java Native ...在实际开发中,理解JNI的工作原理和正确管理内存至关重要,以避免可能出现的内存泄漏和异常。同时,需要注意的是,频繁的JNI调用会增加应用程序的复杂性,并可能影响性能,因此应当适度使用。
这个压缩包通常包含了该版本的所有必要的组件和文件,便于用户...然而,使用它需要对Java和.NET的互操作有一定了解,以及对JNI原理的熟悉。通过不断学习和实践,开发者可以充分利用jni4net带来的便利,提高开发效率。
通过深入学习和实践这些文档,开发者不仅能理解JNI的工作原理,还能熟练地编写混合Java和本地代码的应用程序。同时,理解和遵守JNI编程规范能确保代码的可维护性和健壮性,避免潜在的问题,如内存泄漏、线程安全问题...
`C++ GUI Programming with Qt 4.chm`可能就是一本关于如何使用C++和Qt创建GUI的参考资料,虽然没有直接提供关于JNI的细节,但它可以帮助理解C++和GUI编程的基本原理,这对于在Java中通过JNI调用Qt库是非常有帮助的...
2. **JNI开发流程**: 开发JNI程序通常包括以下步骤:编写Java类并声明native方法,使用javah工具生成C/C++头文件,实现头文件中的函数,将实现的本地库编译为.so动态链接库,最后在Java代码中加载并调用本地方法。...
2. **Android与JNI**: 在Android系统中,JNI被广泛用于提高性能、访问底层硬件和利用已有的C/C++库。由于Android的Dalvik/ART虚拟机支持JNI,所以开发者可以创建本地库,然后在Android应用中通过JNI接口调用。 3....
2. **在JNI中开启线程**: JNI本身并不直接支持创建线程,但我们可以使用C/C++原生的线程API(如POSIX的`pthread_create`或Windows的`CreateThread`)来实现。以下是一个简单的示例: ```c++ #include void* ...
2. **引用分析**:它检查JNI函数中是否存在对Java对象的长期引用,这些引用可能导致对象无法被垃圾回收。 3. **内存泄漏检测**:当Java对象被JNI层引用但不再被Java代码使用时,LeakTracer会将其标记为潜在的内存...
JNI,全称Java Native Interface,是...通过阅读这些书籍,可以系统地理解JNI的工作原理,学习如何在Java和本地代码之间建立桥梁,从而在各种复杂场景下灵活地融合Java和C/C++的优点,实现高性能、跨平台的应用程序。
NDK(Native Development Kit)是Android平台提供的一套工具,用于让...通过这个"NDK JNI开发例子代码2",开发者可以深入学习如何在Android应用中高效地利用C/C++代码,提升应用性能,同时理解和掌握JNI的工作原理。
知识点2:JNI 设计原理 * JNI 的设计原理:JNI 的设计原理是基于 Java 虚拟机和本地库之间的接口,允许 Java 代码调用本地代码,本地代码也可以调用 Java 代码。 * JNI 的实现细节:JNI 的实现细节包括了 Java ...
本讲解将深入探讨JNI的第1、2讲中的核心概念和技术细节。 在第一讲中,我们将首先理解JNI的基本架构和工作原理。JNI提供了一套接口,使得Java代码能够声明和调用本地方法(即非Java语言编写的函数)。这些本地方法...
本篇文章将通过分析“JniDemo_H246分析_DEMO_jni测试”项目,深入探讨JNI的基本概念、工作原理以及在实际应用中的关键步骤。 首先,我们需要理解JNI的核心概念。JNI为Java开发者提供了一种机制,使得Java代码能够...
2. **实现自定义的Java虚拟机**:理解JNI的工作原理有助于开发者设计出更高效、更灵活的Java虚拟机。 3. **跨语言协作**:了解JNI如何处理垃圾回收、多线程等高级特性,对于构建复杂的多语言系统至关重要。 4. **...
2. **初始化处理**:`JNI_OnLoad()`函数还可以用于进行必要的初始化工作。例如,在`libmedia_jni.so`库中,开发者可以通过`JNI_OnLoad()`函数注册一些本机方法,以便Java层能够调用这些方法。下面是一个示例代码片段...