Linux下,JNI的应用例程解析(一)——Java调用C库

说明:本文借助一个简单的Holle World例程,在Linux平台上演示如何使用JNI,实现Java调用C的库。

JIN说明

JNI是Java native interface的简写,可以译作Java原生接口。

Java可以通过JNI调用C/C++的库,这对于那些对性能要求比较高的Java程序无疑是一个福音。

JNI是Java与C/C++交互的接口。

      使用JNI也是有代价。大家都知道JAVA程序是运行在JVM之上的,可以做到平台无关。

但是如果Java程序通过JNI调用了原生的代码(比如c/c++等),则Java程序就丧失了平台无关性。

最起码需要重新编译原生代码部分。所以应用JNI需要好好权衡,不到万不得已,请不要选择JNI,

 

1.编写TestJni.java文件

package mdjpos.testjni;//指定根目录位置

import java.util.*;

	
public class TestJni
{
//native关键字表明方法是用其他语言实现的
	public native void print(String content);

	static
	{
		System.loadLibrary("TestJni");
		// load native library exclude extension name.
	}
}

注意print方法的声明,关键字native表明该方法是一个原生代码实现的。

另外注意static代码段的System.loadLibrary调用,这段代码表示在程序加载的时候,自动加载libTestJni.so库。

 

TestJni.c文件保存路径:  ***jni_test\mdjpos\testjni

说明:***为省略的工程文件夹所在的路径,jni_test为工程的根目录文件。

 

2.生成 TestJni.h文件

(1)执行命令:javah -jni -d ./so_src mdjpos.testjni.TestJni

javah:shell指令,用于生成".h"文件

-jni:生成JIN样式的标头文件(默认值)

-d ./so_src:指定输出文件的路径为:./so_src

mdjpos.testjni.TestJni:头文件名和函数名

扩展:可以输入“javah -help”,查询javah的用法。

 在jni_test\so_src下,可查看到生成的头文件mdjpos_testjni_TestJni.h。

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

#ifndef _Included_mdjpos_testjni_TestJni
#define _Included_mdjpos_testjni_TestJni
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     mdjpos_testjni_TestJni
 * Method:    print
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_mdjpos_testjni_TestJni_print
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

 

(2)修改头文件名

将文件名“mdjpos_testjni_TestJni.h”改成“TestJni.h”。

 

3.创建TestJni.c文件

#include <jni.h>
#include <stdio.h>
#include <TestJni.h>

JNIEXPORT void JNICALL
      Java_mdjpos_testjni_TestJni_print(JNIEnv *env,jobject obj, jstring content)
{
	// 从 instring 字符串取得指向字符串 UTF 编码的指针
	//注意C语言必须(*env)->		  C++ env->

	const jbyte *str =(const jbyte *)(*env)->GetStringUTFChars(env,content, JNI_FALSE);

	printf("Hello---->%s\n",str);

	// 通知虚拟机本地代码不再需要通过 str 访问 Java 字符串。
	(*env)->ReleaseStringUTFChars(env, content, (const char *)str );

	return;
}

//这里看到  JNIEnv作用了,使得我们可以使用Java的方法

//jobject 指向在此 Java 代码中实例化的 Java 对象 LocalFunction 的一个句柄,相当于 this 指针

参数类型 jstring 对应java中的String,这里是有所不同的。每一个Java里的类型这里有对应的与之匹配。

 

4.生成:libTestJni.so库文件

gcc -I /usr/lib/jvm/java-8-openjdk-amd64/include/linux/ -I /usr/lib/jvm/java-8-openjdk-amd64/include/ -I ./so_src/ -fPIC -shared -o ./libs/libTestJni.so ./so_src/TestJni.c

-I /usr/lib/jvm/java-8-openjdk-amd64/include/linux/:指定头文件路径。(这里具体对应哪个头文件暂时还不清楚,望大神指教)

-I /usr/lib/jvm/java-8-openjdk-amd64/include/:指定头文件“jni.h”的路径。

-I ./so_src/:指定头文件“TestJni.h”的路径。

-fPIC:作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code),则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意位置,都可以正确的执行。

-shared:生成动态库

-o ./libs/libTestJni.so:指定生成库文件的路径和名称。

./so_src/TestJni.c:指定源文件的路径和名称。

 

5.创建Test_main.java文件

import java.util.*;

import mdjpos.testjni.*;
	
public class Test_main
{
	public Test_main()
	{
	
	}
	
     public static void main(String argv[])
     {
	   	TestJni m_TestJni;
	   	m_TestJni = new TestJni();
	  	m_TestJni.print("Hello,World !");
     }


}

编译, javac Test_main.java

 

6.运行

java -Djava.library.path=./libs Test_main

 java :运行指令。

-Djava.library.path=./libs :指定动态库文件路径。

Test_main:运行的class文件名。

 7.常见错误

问题:未找到动态库文件。
原因:动态库文件的路径错误,未查找到库。将“./”改成“./libs”,动态库文件不在根目录,在根目录下的libs文件中。

参考文件:https://blog.csdn.net/yanhe156/article/details/80521553

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值