一、关于JNI

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

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

二、实现步骤

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

 //文件:Ctest.java
public class Ctest{
static
{
System.loadLibrary("myself");
}
public native void testJNI(); //声明
public static void main(String[] args)
{
Ctest test=new Ctest ();
test. testJNI ();
}
}

代码折叠

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

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

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

 /* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Ctest */ #ifndef _Included_Ctest
#define _Included_Ctest
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Ctest
* Method: testJNI
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_Ctest_testJNI(JNIEnv *, jobject); #ifdef __cplusplus
}
#endif
#endif

代码折叠

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

 #include <stdio.h>
#include "Ctest.h"
JNIEXPORT void JNICALL Java_Ctest_testJNI(JNIEnv *env, jobject obj)
{
printf("\ntesting jni .............\n");
printf(".........................\n");
}

代码折叠

(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内容:

 libmyself.so:myself.o
gcc -Wall -rdynamic -shared -o libmyself.so myself.o
%.o:%.c
gcc -I/usr/lib/jvm/jdk--oracle-arm-vfp-hflt/include/ -I/usr/lib/jvm/jdk--oracle-arm-vfp-hflt/include/linux/ -fPIC -c -o $@ $^
clean:
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头文件中的函数来实现数据的传递。例如:

 //file:testJNI.java
import java.util.Arrays;
public class testJNI{
static
{
System.loadLibrary("myself");
}
private byte[] mybuf; public native void setBuffer(byte[] buffer,int len);
public native byte[] getBuffer();
public testJNI()
{
mybuf = new byte[30];
}
public static void main(String[] args)
{
int i;
byte a;
byte[] pbuf;
a = 'e';
testJNI test=new testJNI();
for(i=0;i<10;i++)
test.mybuf[i] = a;
test.setBuffer(test.mybuf,10);
pbuf = test.getBuffer();
for(i=0; i<10; i++)
System.out.print(pbuf[i]+",");
System.out.print('\n');
}
}

testJNI.java代码折叠

 /* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class testJNI */ #ifndef _Included_testJNI
#define _Included_testJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: testJNI
* Method: setBuffer
* Signature: ([BI)V
*/
JNIEXPORT void JNICALL Java_testJNI_setBuffer(JNIEnv *, jobject, jbyteArray, jint); /*
* Class: testJNI
* Method: getBuffer
* Signature: ()[B
*/
JNIEXPORT jbyteArray JNICALL Java_testJNI_getBuffer(JNIEnv *, jobject); #ifdef __cplusplus
}
#endif
#endif

testJNI.java代码折叠

 #include <stdio.h>
#include "testJNI.h" JNIEXPORT void JNICALL Java_testJNI_setBuffer(JNIEnv *env, jobject obj, jbyteArray buffer, jint len)
{
int i;
char table[30];
char *ptab;
printf("\ntesting jni array.............\n"); //这个函数是将java里的数组拷贝到C这边,执行完table获得java传过来的数组值
(*env)->GetByteArrayRegion(env,buffer,0,len,table);
for(i=0;i<len;i++)
printf("table[%d]=%c,",i,table[i]);
printf("\n");
/*
* 也可以使用这个函数,将本地的指针ptab直接指向Java端的数组地址,
* 其实本质上是JVM在堆上分配的这个数组对象上增加一个引用计数,保证
* 垃圾回收的时候不要释放,从而交给本地的指针使用,使用完毕后指针
* 一定要记得通过ReleaseByteArrayElements进行释放,否则会产生内存泄露。
*/
ptab = (*env)->GetByteArrayElements(env,buffer,0);
if(ptab ==NULL)
{
printf("ReleaseByteArrayElements error.\n");
return ;
}
for(i=0;i<len;i++)
printf("ptab[%d]=%c,",i,ptab[i]);
printf("\n");
(*env)->ReleaseByteArrayElements(env,buffer,ptab,0);
} JNIEXPORT jbyteArray JNICALL Java_testJNI_getBuffer(JNIEnv *env, jobject obj)
{
int i;
char buffer[30];
for(i=0;i<10;i++)
buffer[i] = 'a';
// 在JNI层分配数组空间
jbyteArray array = (*env)->NewByteArray(env,30);
// 将buffer值复制给JNI层数组
(*env)->SetByteArrayRegion(env,array,0,10,buffer);
// 返回访问指针
return array;
// 此外还有一种方法可以实现,使用GetDirectBufferAddress()函数
}

myself.c代码折叠

 libmyself.so:myself.o
gcc -Wall -rdynamic -shared -o libmyself.so myself.o %.o:%.c
gcc -I/usr/lib/jvm/java--openjdk-amd64/include/ -I/usr/lib/jvm/java--openjdk-amd64/include/linux/ -fPIC -c -o $@ $^ clean:
rm -rf *.o *.so

Makefile代码折叠

Java调用C函数的更多相关文章

  1. Android使用JNI(从java调用本地函数)

    当编写一个混合有本地C代码和Java的应用程序时,需要使用Java本地接口(JNI)作为连接桥梁.JNI作为一个软件层和API,允许使用本地代码调用Java对象的方法,同时也允许在Java方法中调用本 ...

  2. java调用matlab函数

    如何将实验结果在matlab中可视化呢,下面使用java语言编程,调用matlab中的函数: 本人安装的是Matlab7.11.0 (R2010a)和 Eclipse 4.2 : 1)首先设置环境变量 ...

  3. Java 调用 Javascript 函数的范例

    在Java 7 以后,可以在Java代码中调用javascript中的函数,请看下面的例子: package com.lee; import java.io.FileNotFoundException ...

  4. Linux平台下Java调用C函数

    JNI是Java native interface的简写,可以译作Java原生接口.Java可以通过JNI调用C/C++的库,这对于那些对性能要求比较高的Java程序无疑是一个 福音. 使用JNI也是 ...

  5. java调用js函数

    问题:js函数可能有多个,之间有相互调用关系,有jquery jar包 org.mozilla.javascript-1.7.2 js   envjs-1.2.js java代码 import jav ...

  6. java调用c++函数的简单笔记

    java使用jni调用c++动态库函数. 步骤: 1.编写java测试代码如下: public class CallNativeDemo { native void func(); native do ...

  7. java调用oracle函数

    /** * 调用函数取得数据表的ID值 * @param tableName 表名 * @return * @throws SQLException */ public String callFun( ...

  8. Android JNI之JAVA调用C/C++层

    转载请声明:原文转自:http://www.cnblogs.com/xiezie/p/5929996.html 一.java调用本地函数的开发步骤: 1.编写本地方法的类(可以说是用来叙述本地方法的类 ...

  9. JAVA调用c/c++代码

    JNI是Java Native Interface的缩写,中文为JAVA本地调用.使用JNI可以很方便的用我们的Java程序调用C/C++程序.很多时候,某些功能用Java无法实现,比如说涉及到底层驱 ...

随机推荐

  1. Redis数据结构(四)

    存储list: list存储方式采用头和尾插入的方式,这样效率快,如果没有这个插入的数据,redis自己会创建这个数据,如果是中间插入的话,采用list方式效率就会很慢. ArrayList使用数组方 ...

  2. POJ 1739 Tony's Tour (DP)

    题意:从左下角到右下角有多少种走法. 析:特殊处理左下角和右下角即可. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000 ...

  3. underscore collections

    1._.each(list, iterator, [context]):对集合中每一元素执行处理器方法. 如果传递了context参数,则把iterator绑定到context对象上.每次调用iter ...

  4. [label][IDE] Develop Node.js Project With WebStorm

    WebStorm 是一个支持 Node.js,CoffeeScript, TypeScript, Dart, Jade, Sass, LESS and Stylus 这些最新 web 开发技术的集成开 ...

  5. dxbarmanager生成传统下拉式样的菜单

    传统菜单 //创建一个dxSubItem,相当于创建一个主菜单项 dxBarSubItem := TdxBarSubItem.Create(Self); dxBarSubItem.Caption := ...

  6. mysql多个TimeStamp设置(转)

    timestamp设置默认值是Default CURRENT_TIMESTAMP timestamp设置随着表变化而自动更新是ON UPDATE CURRENT_TIMESTAMP 但是由于 一个表中 ...

  7. MSSQL中通过关键字查找所有存储过程

    select b.namefrom 数据库名.dbo.syscomments a, 数据库名.dbo.sysobjects bwhere a.id=b.id and b.xtype='p' and a ...

  8. 手动编译安装lamp之mysql

    转自马哥教育的讲课文档 二.安装mysql-5.5.28 1.准备数据存放的文件系统 新建一个逻辑卷,并将其挂载至特定目录即可.这里不再给出过程. 这里假设其逻辑卷的挂载目录为/mydata,而后需要 ...

  9. JAVA 字符串编码转换

    /** * 字符串编码转换的实现方法 * @param str 待转换编码的字符串 * @param newCharset 目标编码 * @return * @throws UnsupportedEn ...

  10. leetcode 合并两个有序数组

    给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组. 说明: - 初始化 nums1 和 nums2 的元素数量分别为 m 和 ...