linux下实现jni的方式
用JNI实现一个经典的“Hello World”程序。该程序在Java中通过JNI调用c函数实现“Hello World”的输出。创建该程序分为以下步骤:
1、创建一个Java程序(HelloWorld.java)定义原生的c/c++函数。
创建java文件,声明native方法
2、用javac编译HelloWorld.java生成HelloWorld.class。
编译java文件 javac HelloWorld.java
3、用javah带-jni参数编译HelloWorld.class生成HelloWorld.h文件,该文件中定义了c的函数原型。在实现c函数的时候需要。
生成头文件 javah -jni HelloWorld 会生成HelloWorld.h文件
4、创建HelloWorld.c,实现HelloWorld.h定义的函数。
根据HelloWorld.h文件创建c文件,并实现方法
注意:
1.需要将jni.h和jni_md.h拷贝至工程目录下
2.将HelloWorld.h文件中的#include <jni.h>系统应用改为 #include "jni.h"
3.补全方法参数(env , obj),完成c代码的实现
5、编译HelloWorld.c生成libHelloWorld.so。
执行如下命令:
gcc -I/usr/lib/jvm/java-6-sun/include/linux/ -I/usr/lib/jvm/java-6-sun/include/ -I/home/user/Downloads/JNITest/AAA -fPIC -shared -o libHelloWorld.so HelloWorld.c
参数解释:
-shared:该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件
-fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的
-I/usr/lib/jvm/java-6-sun/include/linux/ : 表示在编译HelloWorld.c时,将此目录作为第一个寻找头文件的目录
注意:
编译完成的库文件名称(eg:libHelloWorld.so)必须命名格式为:(libxxx.so) , 加载动态库时格式如下:
//加载动态库
static{
System.loadLibrary("xxx"); //不需要加lib字段,直接加载xxx即可
}
6、在java虚拟机运行java程序HelloWorld。
java HelloWorld 执行java程序
注意:如果报错:java.lang.UnsatisfiedLinkError ?
通过指明共享库的路径的方式执行:java -Djava.library.path='.' HelloWorld
c代码:HelloWorld.c
#include <stdio.h>
#include "HelloWorld.h"
JNIEXPORT void JNICALL Java_HelloWorld_print
(JNIEnv *env, jobject type) {
//JNIEnv 结构体指针
//代表java运行环境,调用java中的代码
printf("\nstring from method in JNI c \n\n");
//通过FindClass找到对应的类
jclass jniHandle = (*env)->FindClass(env, "HelloWorld");
//GetStaticMethodID找到对应方法的ID
//第二个参数为查找方法的类class,
//第三个参数为查找方法名称,
//第四个参数为方法参数和返回值类型 ()代表此方法没有参数,Ljava/lang/String代表返回string类型
jmethodID getStringFromStatic = (*env)->GetStaticMethodID(env, jniHandle, "getStringFromStatic", "()Ljava/lang/String;");
//调用方法,(静态)传入类即可
jstring result = (*env)->CallStaticObjectMethod(env, jniHandle, getStringFromStatic);
//字符串转换
const char *resultChar = (*env)->GetStringUTFChars(env, result, NULL);
//释放引用
(*env)->DeleteLocalRef(env, result);
printf("%s\n\n",resultChar);
//若调用非静态方法时,需要先构造类的对象
//获取构造方法id
jmethodID constructor = (*env)->GetMethodID(env, jniHandle, "<init>", "()V");
//创建类的对象<传入类和构造方法id>
jobject jniHandleObject = (*env)->NewObject(env, jniHandle, constructor);
//找到非静态方法的id
jmethodID getStringForJava = (*env)->GetMethodID(env, jniHandle, "getStringForJava", "()Ljava/lang/String;");
//调用方法,(非静态)传入类的对象和对象的方法id
jstring result2 = (*env)->CallObjectMethod(env, jniHandleObject, getStringForJava);
//字符串转换,释放引用
const char *resultChar2 = (*env)->GetStringUTFChars(env, result2, NULL);
(*env)->DeleteLocalRef(env, jniHandle);
(*env)->DeleteLocalRef(env, jniHandleObject);
(*env)->DeleteLocalRef(env, result2);
printf("%s\n\n",resultChar2);
}
/*
java代码:
class HelloWorld
{
private native void print();
public static void main(String[] args)
{
new HelloWorld().print();
}
static
{
System.loadLibrary("HelloWorld");
}
public static String getStringFromStatic() {
return "string from static method in java";
}
public String getStringForJava() {
return "string from method in java";
}
}
编译命令:
javac HelloWorld.java
javah -jni HelloWorld
gcc -I/usr/lib/jvm/java-6-sun/include/linux/ -I/usr/lib/jvm/java-6-sun/include/ -fPIC -shared -o libHelloWorld.so HelloWorld.c
java -Djava.library.path='.' HelloWorld
*/