来自2023年的温馨提示:
感谢各位的支持,这是我十年前还在读大学时写的文章了,技术日新月异的今天希望大家不要被我的旧文章误导了,有时间我再更新该文章
我们知道Java是一个运行在虚拟机里面的高级的编程语言,如果要调用系统的动态链接库的话,就要先声明native修饰的方法(类似接口里面的方法),再由C/C++程序来实现(类似实现接口里的方法)。这样Java调用这些native方法就相当于调用了C/C++里面实现了的方法。通常我们把这种机制叫做JNI(Java NativeInterfac),即Java 本地编程接口
Android也同理,要学会在Android上进行NDK开发,首先我们到打好java JNI的基础。现在我们暂时把Android开发丢到一边先,试试在Java之下编译一个C动态链接库,再用Java程序调用。
1)先来个最简单的打印HelloWorld例子:
Java代码(HelloJni.java):
import java.util.*; public class HelloJni{ static{ System.loadLibrary("hello"); } public native static void sayHello(); public static void main(String [] args) { HelloJni.sayHello(); } }
生成头文件(HelloJni.h):
先javac HelloJni.java编译你的Java源码,再javah–jni HelloJni生成所需的头文件
头文件内容是这样的:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class HelloJni */ #ifndef _Included_HelloJni #define _Included_HelloJni #ifdef __cplusplus extern "C" { #endif JNIEXPORT void JNICALL Java_HelloJni_sayHello (JNIEnv *, jclass); #ifdef __cplusplus } #endif #endif
实现头文件声明的方法(HelloJni.cpp)
#include "HelloJni.h" JNIEXPORT void JNICALL Java_HelloJni_sayHello(JNIEnv *env, jclass cls) { printf("HelloWorld"); }
编译命令: g++ -I$JAVA_HOME/include-I$JAVA_HOME/include/linux HelloJni.cpp -shared -o libhello.so
命令参数解析:-I 是指引入java虚拟机的库的路径,-shared 是指编译成动态链接库(共享库) –o 输出文件名(注意,在Linux平台下的动态链接库有一个命名格式:“lib+库名+.so”在java代码里面loadLibrary的时候不要加lib前缀和.so后缀)
由于我这里把这个动态链接库编译放在当前目录下,所以还要设置环境变量LD_LIBRARY_PATH=该so动态链接库所在的目录,才能正常运行
#############################+++华丽的分割线+++###########################
2)好了,可以打印HelloWorld出来后,我们再深入一点点,传入一个int的数,在C/C++代码里面加1后返回。
Java代码(HelloJni.java):
public class HelloJni{ static{ System.loadLibrary("hello"); } public static native void sayHello(); public native int getInt(); public native void setInt(int i); public static void main(String args[]){ // HelloJni.sayHello(); HelloJni hello = new HelloJni(); hello.setInt(2); System.out.println(hello.getInt()); } }
生成头文件(HelloJni.h):