`
king_tt
  • 浏览: 2108535 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Linux下jni实现

 
阅读更多
最近研究Android,涉及到JNI调用。虽然我对Java语言有所了解,但是还没有接触过JNI。今天在Unix Center的Ubuntu上面用JNI实现了“经典”的“Hello world”程序。通过这个简单的程序把JNI的一些小知识进行一下总结。

什么是JNI

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

使用JNI也是有代价。大家都知道JAVA程序是运行在JVM之上的,可以做到平台无关。但是如果Java程序通过JNI调用了原生的代码(比如c/c++等),则Java程序就丧失了平台无关性。最起码需要重新编译原生代码部分。所以应用JNI需要好好权衡,不到万不得已,请不要选择JNI,可以选择替代方案,比如TCP/IP进行进程间通讯等等。这也是为什么谷歌的Android平台的底层虽然用JNI实现,但是他不建议开发人员用JNI来开发Android上面的应用的原因。将会丧失Android上面的应用程序平台无关性。

JNI的简单示例

下面我就用JNI实现一个经典的“Hello World”程序。该程序在Java中通过JNI调用c函数实现“Hello World”的输出。创建该程序分为以下步骤:

1、创建一个Java程序(HelloWorld.java)定义原生的c/c++函数。

2、用javac编译HelloWorld.java生成HelloWorld.class。

3、用javah带-jni参数编译HelloWorld.class生成HelloWorld.h文件,该文件中定义了c的函数原型。在实现c函数的时候需要。

4、创建HelloWorld.c,实现HelloWorld.h定义的函数。

5、编译HelloWorld.c生成libHelloWorld.so。

6、在java虚拟机运行java程序HelloWorld。

下面我们就一步一步来实现这个程序。

创建HelloWorld.java

class HelloWorld
{
	private native void print();
	public static void main(String[] args)
	{
		new HelloWorld().print();
	}

	static
	{
		System.loadLibrary("HelloWorld");
	}
}

注意print方法的声明,关键字native表明该方法是一个原生代码实现的。另外注意static代码段的System.loadLibrary调用,这段代码表示在程序加载的时候,自动加载libHelloWorld.so库。

编译HelloWorld.java

在命令行中运行如下命令:

javac HelloWorld.java

在当前文件夹编译生成HelloWorld.class。

生成HelloWorld.h

在命令行中运行如下命令:

javah -jni HelloWorld

在当前文件夹中会生成HelloWorld.h。打开HelloWorld.h将会发现如下代码:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloWorld */

#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     HelloWorld
 * Method:    print
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_HelloWorld_print
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

该文件中包含了一个函数Java_HelloWorld_print的声明。这里面包含两个参数,非常重要,后面讲实现的时候会讲到。

实现HelloWorld.c

创建HelloWorld.c文件输入如下的代码:

#include <jni.h>
#include <stdio.h>
#include "HelloWorld.h"

JNIEXPORT void JNICALL 

    Java_HelloWorld_print(JNIEnv *env, jobject obj)
{
	printf("Hello World!\n");
}

注意必须要包含jni.h头文件,该文件中定义了JNI用到的各种类型,宏定义等。

另外需要注意Java_HelloWorld_print的两个参数,本例比较简单,不需要用到这两个参数。但是这两个参数在JNI中非常重要。

env代表java虚拟机环境,Java传过来的参数和c有很大的不同,需要调用JVM提供的接口来转换成C类型的,就是通过调用env方法来完成转换的。

obj代表调用的对象,相当于c++的this。当c函数需要改变调用对象成员变量时,可以通过操作这个对象来完成。

编译生成libHelloWorld.so

在Linux下执行如下命令来完成编译工作:

cc -I/usr/lib/jvm/java-6-sun/include/linux/
   -I/usr/lib/jvm/java-6-sun/include/
    -fPIC -shared -o libHelloWorld.so HelloWorld.c

在当前目录生成libHelloWorld.so。注意一定需要包含Java的include目录(请根据自己系统环境设定),因为Helloworld.c中包含了jni.h。

另外一个值得注意的是在HelloWorld.java中我们LoadLibrary方法加载的是“HelloWorld”,可我们生成的Library却是libHelloWorld。这是Linux的链接规定的,一个库的必须要是:lib+库名+.so。链接的时候只需要提供库名就可以了。

运行Java程序HelloWorld

大功告成最后一步,验证前面的成果的时刻到了:

java HelloWorld

如果你这步发生问题,如果这步你收到java.lang.UnsatisfiedLinkError异常,可以通过如下方式指明共享库的路径:

java -Djava.library.path='.' HelloWorld

当然还有其他的方式可以指明路径请参考《在Linux平台下使用JNI》。

我们可以看到久违的“Hello world!”输出了。

总结

本文只是一个JNI简单调用,当然JNI还有很多东西需要学习。如有错误之处请不吝指教。

分享到:
评论

相关推荐

    如何在linux操作系统下使用JNI

    一步步说明在 Linux 平台下如何实现本地共享库与 Java 协同工作

    springboot 集成seetaface6JNI实现人脸检测识别

    springboot 集成seetaface6JNI实现人脸检测识别,

    linux 安卓 JNI UDP局域网广播

    linux下的UPD广播,改造后可以用于安卓JNI调用,搜索局域网内的手机,本例重点在学习于局域网UDP广播,不妥之处欢迎指正。 由于完整代码在家中电脑,随和我会放上完整的安卓JNI调用c++实现局域网广播搜索所有wifi连...

    如何利用JNI实现Java插件开发

    本文主要工作在于利用JNI实现对已经完成的视频镜头提取C++程序的调用。  整个过程如下所示:  (1)将视频特征提取算法建立相应的windows下的Dll和Linux下的So(这个两个文件大家都知是什么了吧)  (2)利用jni...

    linux C JNI调用java

    次资源完美的实现linux环境下C语言调用java类里面的函数,包括jdk的下载安装配置,java类的编写编译,C语言调用java类的demo代码实现,代码的编译及测试。

    Java JNI调用动态库(Linux、Windows)的实现步骤

    Java JNI调用动态库(Linux、Windows)的实现步骤

    JNI实现的DEMO Java调用VC编写的DLL,对应于Linux .SO

    JNI实现的DEMO Java调用VC6编写的DLL,对应于Linux .SO 包含C的项目和Java的Eclipse项目

    java 通过jni技术实现获取linux的硬盘序列号.pdf

    java 通过jni技术实现获取linux的硬盘序列号.pdf,如果文档看不明白可以联系本人

    CTP的JNI封装

    (3)src是CTP的JNI接口实现,已经写好了Makefile,熟悉C的人,看着Makefile把缺的库放到合适的位置就可以编译Ok了。 (4)由于JNI的特殊性,依赖的库文件都统一放到编译链接时的库文件目录,如/usr/lib 特别说明: 平台:...

    Linux标准输入、输出和重定向

    执行一个shell命令行时通常会自动打开三个标准文件,即标准输入文件(stdin),通常对应终端的键盘;标准输出文件(stdout)和标准错误输出文件(stderr),这两个文件都对应终端的屏幕。进程将从标准输入文件中得到...

    JNI模拟系统事件

    原理是在jni中通过Linux内核的ioctl函数和c语言函数(memset、write)来实现对设备的I/O通道进行管理的。所谓对I/O通道进行管理,就是对设备的一些特性进行控制,例如串口的传输波特率、马达的转速等等。

    JNI(java-c).rar_C/C++层回调Java_JAVA LINUX so_NDK SO_java jni linux

    1.hello-jin-c是linux下的c实现文件。 (使用NDK编译成.so文件,供java层调用)。 2.helloJni是java工程。(里面通过JNI调用下面.so中提供的c的实现。) 同理.so里面也可以调用回调java里面实现的文件。

    dynamic_register_jni.zip

    3、动态注册是在JNi层实现的,JAVA层不需要关心,因为在system.load时就会去调用JNI_OnLoad,有就注册,没有就不注册。动态注册的原理:JNI 允许我们提供一个函数映射表,注册给 JVM,这样 JVM 就可以用函数映射表来...

    【jni】linux 下生成 jni 并进行测试

    文件目录 ...第一步, 通过 JNIDemo.java 文件生成接口函数 , .h 文件... //定义一个方法,该方法在C中实现 public native void testHello(); public static void main(String[] args){ //加载C文件 System.loadLibr

    Android APP 用interface 接口的形式对jni进行回调,实例测试

    Android APP 用interface 接口的形式对jni进行回调,实例测试

    Android通过JNI实现守护进程

    开发一个需要常住后台的App其实是一件非常头疼的事情,不仅要应对国内各大厂商的ROM,还需要应对各类的安全管家…虽然不断的研究各式各样的方法,但是效果并不好,比如任务管理器把App干掉,服务就起不来了… ...

    android jni 实现本地加解密数据,使用C++语言编写 ,基于openssl实现 .zip

    对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】: 有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 鼓励下载和使用,并欢迎大家互相学习,共同...

    Android 基于 openssl 1.1.0f版本jni实现加解密.zip

    对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】: 有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 鼓励下载和使用,并欢迎大家互相学习,共同...

    自动更根据Java文件生成JNI接口(C++虚类)的小工具

    自动更根据Java文件生成JNI接口(C++虚类)的小工具, 该工具是运行在UNIX/Linux之上的,内有源码。 工具的实现用到了shell、c语言以及c和java工具链。 压缩包里面有README.TXT可以看说明,有一个范例JniCore.java....

    Android、Windows、Linux下实现c++与java交互

    Android、Windows、Linux下实现c++与java交互,中间件技术

Global site tag (gtag.js) - Google Analytics