• Java调用C函数


    一、关于JNI

          JNI( Java Native Interface )主要是实现Java和C/C++语言之间的通信。

          Java通过JNI调用本地方法,而本地方法是以库文件的形式存放的(在WINDOWS平台上是DLL文件形式,UNIX机器上是SO文件形式)。通过调用本地的库文件的内部方法,使Java可以实现和本地机器的紧密联系,调用系统级的各接口方法。

    二、实现步骤

    (1)把Java中需要的调用的方法加上native关键字,封装到一个类里边。例如:

     1 //文件:Ctest.java
     2 public class Ctest{
     3     static
     4     {
     5         System.loadLibrary("myself");
     6     }
     7     public native void testJNI();     //声明
     8     public static void main(String[] args) 
     9     {        
    10         Ctest test=new Ctest ();
    11         test. testJNI ();
    12     }
    13 }
    代码折叠

    注意:全局类要用类名来定义文件名

    (2)使用javac Ctest.java编译代码,生成对应的类文件Ctest.class。

    (3)使用javah Ctest生成Ctest.h文件,javah后边跟的是类名字,.h文件里边就是使用jni规则定义的C语言与Java的接口。内容如下:

     1 /* DO NOT EDIT THIS FILE - it is machine generated */
     2 #include <jni.h>
     3 /* Header for class Ctest */
     4 
     5 #ifndef _Included_Ctest
     6 #define _Included_Ctest
     7 #ifdef __cplusplus
     8 extern "C" {
     9 #endif
    10 /*
    11  * Class:     Ctest
    12  * Method:    testJNI
    13  * Signature: ()V
    14  */
    15 JNIEXPORT void JNICALL Java_Ctest_testJNI(JNIEnv *, jobject);
    16 
    17 #ifdef __cplusplus
    18 }
    19 #endif
    20 #endif
    代码折叠

    (4)根据Ctest.h中函数的声明来实现函数的定义,编写xxx.c文件,把Ctest.h包含进去即可。

    1 #include <stdio.h>
    2 #include "Ctest.h"
    3 JNIEXPORT void JNICALL Java_Ctest_testJNI(JNIEnv *env, jobject obj)
    4 {
    5     printf("
    testing jni .............
    ");
    6     printf(".........................
    ");
    7 }
    代码折叠

    (5)编译c文件,生成动态链接库.so文件

    寻找jni.h和jni_md.h头文件路径:find / -name “*jni.h*”

    Ubuntu12.04系统上:/usr/lib/jvm/java-6-openjdk-amd64/include/ 和

                          /usr/lib/jvm/java-6-openjdk-amd64/include/linux/

    树莓派系统上:/usr/lib/jvm/jdk-8-oracle-arm-vfp-hflt/include/ 和

                        /usr/lib/jvm/jdk-8-oracle-arm-vfp-hflt/include/linux/

    Makefile内容:

    1 libmyself.so:myself.o
    2     gcc -Wall -rdynamic -shared -o libmyself.so myself.o
    3 %.o:%.c
    4     gcc -I/usr/lib/jvm/jdk-8-oracle-arm-vfp-hflt/include/ -I/usr/lib/jvm/jdk-8-oracle-arm-vfp-hflt/include/linux/ -fPIC -c -o $@ $^
    5 clean: 
    6     rm -rf *.o *.so
    代码折叠

    (6)测试结果:完成

    三、问题解决

    问1.什么是JDK?如何选择版本?

    答1. (Java Development Kit) Java语言的软件开发工具包,主要用来编译Java程序;版本选择:

    ①SE(J2SE),standard edition,标准版,是我们通常用的一个版本,从JDK 5.0开始,改名为Java SE。

    ②EE(J2EE),enterprise edition,企业版,使用这种JDK开发J2EE应用程序,从JDK 5.0开始,改名为Java EE。

    ③ME(J2ME),micro edition,主要用于移动设备、嵌入式设备上的java应用程序,从JDK 5.0开始,改名为Java ME。

    问2.JDK的组成有哪些?

    答2. javac – 编译器,将源程序转成字节码

    jar – 打包工具,将相关的类文件打包成一个文件

    javadoc – 文档生成器,从源码注释中提取文档

    jdb – debugger,查错工具

    java – 运行编译后的java程序(.class后缀的)

    appletviewer:小程序浏览器,一种执行HTML文件上的Java小程序的Java浏览器。

    Javah:产生可以调用Java过程的C过程,或建立能被Java程序调用的C过程的头文件。

    Javap:Java反汇编器,显示编译类文件中的可访问功能和数据,同时显示字节代码含义。

    Jconsole: Java进行系统调试和监控的工具

    问3.Java和C语言之间的基本数据类型是如何进行转换的?

    答3.参考这篇博文http://blog.csdn.net/xyang81/article/details/42047899

    问4.Java是如何读C的数组的?又是如何把值写到C语言的数组里?

    答4.通过jni.h头文件中的函数来实现数据的传递。例如:

     1 //file:testJNI.java
     2 import java.util.Arrays;
     3 public class testJNI{
     4     static
     5     {
     6         System.loadLibrary("myself");
     7     }
     8     private byte[] mybuf;
     9     
    10     public native void setBuffer(byte[] buffer,int len);
    11     public native byte[] getBuffer(); 
    12     public testJNI()
    13     {
    14         mybuf = new byte[30];
    15     }
    16     public static void main(String[] args) 
    17     {
    18         int i;
    19         byte a;
    20         byte[] pbuf;
    21         a = 'e';
    22         testJNI test=new testJNI();
    23         for(i=0;i<10;i++)
    24             test.mybuf[i] = a;
    25         test.setBuffer(test.mybuf,10);
    26         pbuf = test.getBuffer();
    27         for(i=0; i<10; i++)  
    28             System.out.print(pbuf[i]+",");
    29         System.out.print('
    ');
    30     }
    31 }
    testJNI.java代码折叠
     1 /* DO NOT EDIT THIS FILE - it is machine generated */
     2 #include <jni.h>
     3 /* Header for class testJNI */
     4 
     5 #ifndef _Included_testJNI
     6 #define _Included_testJNI
     7 #ifdef __cplusplus
     8 extern "C" {
     9 #endif
    10 /*
    11  * Class:     testJNI
    12  * Method:    setBuffer
    13  * Signature: ([BI)V
    14  */
    15 JNIEXPORT void JNICALL Java_testJNI_setBuffer(JNIEnv *, jobject, jbyteArray, jint);
    16 
    17 /*
    18  * Class:     testJNI
    19  * Method:    getBuffer
    20  * Signature: ()[B
    21  */
    22 JNIEXPORT jbyteArray JNICALL Java_testJNI_getBuffer(JNIEnv *, jobject);
    23 
    24 #ifdef __cplusplus
    25 }
    26 #endif
    27 #endif
    testJNI.java代码折叠
     1 #include <stdio.h>
     2 #include "testJNI.h"
     3 
     4 JNIEXPORT void JNICALL Java_testJNI_setBuffer(JNIEnv *env, jobject obj, jbyteArray buffer, jint len)
     5 {
     6     int i;
     7     char table[30];
     8     char *ptab;
     9     printf("
    testing jni array.............
    ");
    10     
    11     //这个函数是将java里的数组拷贝到C这边,执行完table获得java传过来的数组值
    12     (*env)->GetByteArrayRegion(env,buffer,0,len,table);
    13     for(i=0;i<len;i++)
    14         printf("table[%d]=%c,",i,table[i]);
    15     printf("
    ");
    16     /*
    17      * 也可以使用这个函数,将本地的指针ptab直接指向Java端的数组地址,
    18      * 其实本质上是JVM在堆上分配的这个数组对象上增加一个引用计数,保证
    19      * 垃圾回收的时候不要释放,从而交给本地的指针使用,使用完毕后指针
    20      * 一定要记得通过ReleaseByteArrayElements进行释放,否则会产生内存泄露。
    21      */
    22     ptab = (*env)->GetByteArrayElements(env,buffer,0);
    23     if(ptab ==NULL)
    24     {
    25         printf("ReleaseByteArrayElements error.
    ");
    26         return ;
    27     }
    28     for(i=0;i<len;i++)
    29         printf("ptab[%d]=%c,",i,ptab[i]);
    30     printf("
    ");
    31     (*env)->ReleaseByteArrayElements(env,buffer,ptab,0);
    32 }
    33 
    34 JNIEXPORT jbyteArray JNICALL Java_testJNI_getBuffer(JNIEnv *env, jobject obj)
    35 {
    36     int i;
    37     char buffer[30];
    38     for(i=0;i<10;i++)
    39         buffer[i] = 'a';
    40     // 在JNI层分配数组空间
    41     jbyteArray array = (*env)->NewByteArray(env,30);
    42     // 将buffer值复制给JNI层数组
    43     (*env)->SetByteArrayRegion(env,array,0,10,buffer);
    44     // 返回访问指针
    45     return array;
    46     // 此外还有一种方法可以实现,使用GetDirectBufferAddress()函数
    47 }
    myself.c代码折叠
    1 libmyself.so:myself.o
    2     gcc -Wall -rdynamic -shared -o libmyself.so myself.o
    3 
    4 %.o:%.c
    5     gcc -I/usr/lib/jvm/java-6-openjdk-amd64/include/ -I/usr/lib/jvm/java-6-openjdk-amd64/include/linux/ -fPIC -c -o $@ $^
    6 
    7 clean: 
    8     rm -rf *.o *.so
    Makefile代码折叠
  • 相关阅读:
    pip安装超时
    MySQL+Android+JSP(php)的微博程序设计
    json的jar包
    eclipse远程连接不上数据库
    Dialog的Activity形式
    javaBean?
    Android生命周期详解
    四种启动模式
    softMax怎么更加方便地理解
    sqldevelpoer第一次使用出现错误的处理
  • 原文地址:https://www.cnblogs.com/lubiao/p/4717558.html
Copyright © 2020-2023  润新知