http://hi.baidu.com/fengying765/blog/item/7081113e5fde53e555e7233f.html

作为主调方的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()。

在Linux平台上,遵循JNI规范的动态链接库文件名必须以“lib”开头。例如在上面的Java程序中指定的库文件名为“testjni”,则实际的库文件应该命名为“libtestjni.so”。

编译TestJNI.java,并为C程序生成头文件:

java TestJNI.java

javah TestJNI

提供testjni()函数的testjni.c源文件如下。

代码清单15-5 在Linux平台上调用C函数的例程——testjni.c

#include

#include

JNIEXPORT void JNICALL Java_TestJNI_testjni(JNIEnv *env, jobject obj){

printf("haha---------go into c!!!\n");

}

编写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开发。从下一节开始,环境和步骤不再是阐述的重点,将不再花费专门的篇 幅,例程中的关键点将成为我们关注的焦点。

15.2.2.3 传递字符串

到目前为止,我们还没有实现Java程序向C程序传递参数,或者C程序向Java程序传递参数。本例程将由Java程序向C程序传入一个字符串,C程序对该字符串转成大写形式后回传给Java程序。

Java源程序如下。

代码清单15-6 在Linux平台上调用C函数的例程——Sample1

public class Sample1

{

public native String stringMethod(String text);

public static void main(String[] args)

{

System.loadLibrary("Sample1");

Sample1 sample = new Sample1();

String text   = sample.stringMethod("Thinking In Java");

System.out.println("stringMethod: " + text);

}

}

Sample1.java以“Thinking In Java”为参数调用libSample1.so中的函数stringMethod(),在得到返回的字符串后打印输出。

Sample1.c的源程序如下。

代码清单15-7 在Linux平台上调用C函数的例程——Sample1.c

#include

#include

JNIEXPORT jstring JNICALL Java_Sample1_stringMethod(JNIEnv *env, jobject obj, jstring string)

{

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

char cap[128];

strcpy(cap, str);

(*env)->ReleaseStringUTFChars(env, string, str);

int i=0;

for(i=0;i

*(cap+i)=(char)toupper(*(cap+i));

return (*env)->NewStringUTF(env, cap);

}

首先请注意函数头部分,函数接收一个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的函数。

15.2.2.4 传递整型数组

本节例程将首次尝试在JNI框架内启用数组:C程序向Java程序返回一个定长的整型数组成的数组,Java程序将该数组打印输出。

Java程序的源代码如下。

代码清单15-8 在Linux平台上调用C函数的例程——Sample2

public class Sample2

{

public native int[] intMethod();

public static void main(String[] args)

{

System.loadLibrary("Sample2");

Sample2 sample=new Sample2();

int[] nums=sample.intMethod();

for(int i=0;i

System.out.println(nums[i]);

}

}

Sample2.java调用libSample2.so中的函数intMethod()。Sample2.c的源代码如下。

代码清单15-9 在Linux平台上调用C函数的例程——Sample2.c

#include

JNIEXPORT jintArray JNICALL Java_Sample2_intMethod(JNIEnv *env, jobject obj)

{

inti = 1;

jintArray array;//定义数组对象

array = (*env)-> NewIntArray(env, 10);

for(; i<= 10; i++)

(*env)->SetIntArrayRegion(env, array, i-1, 1, &i);

/* 获取数组对象的元素个数 */

int len = (*env)->GetArrayLength(env, array);

/* 获取数组中的所有元素 */

jint* elems = (*env)-> GetIntArrayElements(env, array, 0);

for(i=0; i

printf("ELEMENT %d IS %d\n", i, elems[i]);

return array;

}

Sample2.c涉及了两个jni.h定义的整型数 相关的数据类型:jint和jintArray,jint是在JNI框架内特有的整数类型。程序的第7行开辟出一个长度为10 的jint数组。然后依次向该数组中放入元素1-10。第11行至第16行不是程序的必须部分,纯粹是为了向读者们演示GetArrayLength() 和GetIntArrayElements()这两个函数的使用方法,前者是获取数组长度,后者则是获取数组的首地址以便于遍历数组。

15.2.2.5 传递字符串数组

本节例程是对上节例程的进一步深化:虽然仍然是传递数组,但是数组的基类换成了字符串这样一种对象数据类型。Java程序将向C程序传入一个包含中文字符的字符串,C程序并没有处理这个字符串,而是开辟出一个新的字符串数组返回给Java程序,其中还包含两个汉字字符串。

Java程序的源代码如下。

代码清单15-10 在Linux平台上调用C函数的例程——Sample3

public class Sample3

{

public native String[] stringMethod(String text);

public static void main(String[] args) throws java.io.UnsupportedEncodingException

{

System.loadLibrary("Sample3");

Sample3 sample = new Sample3();

String[] texts = sample.stringMethod("java编程思想");

for(int i=0;i

{

texts[i]=new String(texts[i].getBytes("ISO8859-1"),"GBK");

System.out.print( texts[i] );

}

System.out.println();

}

}

Sample3.java调用libSample3.so中的函数stringMethod()。Sample3.c的源代码如下:

代码清单15-11 在Linux平台上调用C函数的例程——Sample3.c

#include

#include

#include

#define ARRAY_LENGTH 5

JNIEXPORT jobjectArray JNICALL Java_Sample3_stringMethod(JNIEnv *env, jobject obj, jstring string)

{

jclass objClass = (*env)->FindClass(env, "java/lang/String");

jobjectArray texts= (*env)->NewObjectArray(env, (jsize)ARRAY_LENGTH, objClass, 0);

jstring jstr;

char* sa[] = { "Hello,", "world!", "JNI", "很", "好玩" };

int i=0;

for(;i

{

jstr = (*env)->NewStringUTF( env, sa[i] );

(*env)->SetObjectArrayElement(env, texts, i, jstr);//必须放入jstring

}

return texts;

}

第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行中将 其转码后输出。

15.2.2.6 传递对象数组

本节例程演示的是C程序向Java程序传递对象数组,而且对象数组中存放的不再是字符串,而是一个在Java中自定义的、含有一个topic属性的MailInfo对象类型。

MailInfo对象定义如下。

代码清单15-12 在Linux平台上调用C函数的例程——MailInfo

public class MailInfo {

public String topic;

public String getTopic()

{

return this.topic;

}

public void setTopic(String topic)

{

this.topic=topic;

}

}

Java程序的源代码如下。

代码清单15-13 在Linux平台上调用C函数的例程——Sample4

public class Sample4

{

public native MailInfo[] objectMethod(String text);

public static void main(String[] args)

{

System.loadLibrary("Sample4");

Sample4 sample = new Sample4();

MailInfo[] mails = sample.objectMethod("Thinking In Java");

for(int i=0;i

System.out.println(mails[i].topic);

}

}

Sample4.java调用libSample4.so中的objectMethod()函数。Sample4.c的源代码如下。

代码清单15-14 在Linux平台上调用C函数的例程——Sample4.c

#include

#include

#include

#define ARRAY_LENGTH 5

JNIEXPORT jobjectArray JNICALL Java_Sample4_objectMethod(JNIEnv *env, jobject obj, jstring string)

{

jclass objClass = (*env)->FindClass(env, "java/lang/Object");

jobjectArray mails= (*env)->NewObjectArray(env, (jsize)ARRAY_LENGTH, objClass, 0);

jclass objectClass = (*env)->FindClass(env, "MailInfo");

jfieldID topicFieldId = (*env)->GetFieldID(env, objectClass, "topic", "Ljava/lang/String;");

int i=0;

for(;i

{

(*env)->SetObjectField(env, obj, topicFieldId, string);

(*env)->SetObjectArrayElement(env, mails, i, obj);

}

return mails;

}

程序的第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,我们都有涉及。

posted on 2011-07-18 18:36 hijackwust 阅读(4131) 评论(0)  编辑  收藏

java调用c so动态库_jni 调用C动态库dll/so相关推荐

  1. java 动态库_java调用dll动态库文件的一般总结

    前一段时间,在项目需求中,需要调用一下第三方的动态库文件,下面是本人一些尝试的经历. 首先需要明白的是,在java中是不能直接调用动态库文件的,因为动态库文件是使用c或是c++编写的,作为一种跨   ...

  2. vc java动态库_Java调用已经写好的VC++动态链接库

    利有JNI,实现Java调用VC++动态链接库 1.假设已经写好的VC++ DLL叫 decOrEnc.dll 其中有一个方法是 BOOL EncryptFileByKey( PCHAR SrcFil ...

  3. Windows静态库和动态库的调用方法汇总

    静态库的调用方法 第一种:项目设置中引用,在项目的属性中设置.  第二种:在代码中使用 #pragma comment(lib,"lib文件名") 第一种方法:  步骤一:  右键 ...

  4. go语言调用c 的头文件 so,Golang生成共享库(shared library)以及Golang生成C可调用的动态库.so和静态库.a...

    Golang类似于C的静态语言,效率也接近于C,如果Golang也可以导出可供C调用的库,那可以和很多高级语言say goodbye了,goodbye似乎又有点武断,但至少说,Golang可以做很多事 ...

  5. 我用纯C语言开发的中英文混合分词服务器3.0正式发布,词库190多万词,每秒切分5万+,同时提供 c、java、C#、delphi、js调用范例

    我用纯C语言开发的中英文混合分词服务器3.0正式发布,词库190多万词,每秒切分5万+,同时提供 c.java.C#.delphi.js调用范例 百万商业圈中英文混合分词服务器3.0正式发布, 绝对稳 ...

  6. 静态库和动态库的调用

    静态库和动态库的调用 本篇对于其中的语法基础知识等不再做赘述,着重记录2种库调用的实际操作. 如果想学习什么是静态库,动态库及其区别

  7. 【Java 19】反射 - 反射机制概述、获取Class实例、类的加载与ClassLoader的理解、创建运行时类的对象、获取运行时类的完整结构、调用运行时类的指定结构、动态代理

    反射机制概述.获取Class实例.类的加载与ClassLoader的理解.创建运行时类的对象.获取运行时类的完整结构.调用运行时类的指定结构.动态代理 反射 1 Java反射机制概述 1.1 Java ...

  8. c++与fortran混合语言编程中动态链接库的调用,[转载]C++与Fortran混合语言编程中动态连接库的调用...

    摘 要:介绍了C++和Fortran 90混合语言编程中,在C++中调用Fortran动态连接库(DLL,Dynamic Link Library)的方法以及参量传递.函数调用等的方法. 关键词:混合 ...

  9. python什么模块动态调用链接库_Python调用C/C++动态链接库的方法详解

    本文以实例讲解了Python调用C/C++ DLL动态链接库的方法,具体示例如下: 示例一: 首先,在创建一个DLL工程(本例创建环境为VS 2005),头文件: 1 2 3 4 5 6 7 8 9 ...

最新文章

  1. YII相关知识点记录
  2. Linux下创建与解压zip, tar, tar.gz和tar.bz2文件及该文件压缩对比
  3. GAN作用——在我做安全的看来,就是做数据拟合、数据增强
  4. 图像处理——Edge Boxes边缘检测
  5. Veeam Backup Replication试用(三):配置备份(Backup Job)与恢复(Restore)
  6. 围观一下tp的游戏保护 一
  7. 2014.11.12模拟赛【美妙的数字】| vijos1904学姐的幸运数字
  8. Linux内核设计第四周——扒开系统调用三层皮
  9. hdu 6397 Character Encoding
  10. CCF计算机职业资格认证数字排序问题
  11. html ajax传参数 20,jQuery Ajax传参
  12. 那群“沙雕”年轻人,正在闲鱼上蹦迪
  13. #新技能# ps 简单抠图【持续更新】
  14. Testin云层天咨众测学院开课了!
  15. try 、catch、finally用法总结
  16. 五个成人必看的故事!
  17. 字节跳动前端实习一面
  18. Transformer T5 模型慢慢读
  19. 前端学习--【训练营】Cisco PT Student模拟dhcp自动分配IP地址实现网络互联
  20. Typora主题推荐及资源

热门文章

  1. Java Scanner next()方法与示例
  2. ruby 集合 分组_在Ruby中找到两个集合之间的区别
  3. java上传kafka的方法_哪种方法是将所有数据从Kafka主题复制到接收器(文件或Hive表)的最佳方法?...
  4. switch 字符串 java_JDK7新特性switch支持字符串
  5. python画图显示不了中文_完美解决Python matplotlib绘图时汉字显示不正常的问题
  6. 16位的数字高字节和低字节_显示掩盖较低和较高的16位数字半字节| 8086微处理器...
  7. Java StringBuilder length()方法与示例
  8. if快还是switch快?解密switch背后的秘密
  9. Java面试详解(2020版):500+ 面试题和核心知识点详解
  10. vb读出二进制文件,合并两个文件