1、调用无参函数
java code
public class JNITest {
static {
/*加载*/
System.loadLibrary("mynative");
}
public native static void JavaHello();
public static void main(String[] args) {
/*java c库 函数建立联系*/
/*调用*/
JavaHello();
}
}
C code
#include <stdio.h>
#include <jni.h>
void c_hello() /*C 中将被 Java 调用的函数*/
{
printf("hello, this is my natvie test\n");
}
static const JNINativeMethod methods[] = { /*声明java 和 c 中相关联的函数,和参数*/
{"JavaHello", "()V", (void *)c_hello},
};
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *jvm, void *reserved) /*主要功能是注册c函数到java的运行空间,实现真正的java和c之间的关联*/
{ /*库被加载的时候,该函数被调用*/
JNIEnv *env;
jclass cls;
if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4)) /*获取但前java的版本号*/
{
return JNI_ERR;
}
cls = (*env)->FindClass(env, "JNITest"); /*寻找对应的java class,所以这里的名字一定要和java调用者一样*/
if(cls == NULL)
{
return JNI_ERR;
}
/*java c库 函数建立联系*/
if((*env)->RegisterNatives(env, cls, methods, 1) < 0) /*将 JNINativeMethod 数组注册,实现java函数和C函数的挂接,从而可以通过java函数调用c函数 */
return JNI_ERR;
return JNI_VERSION_1_4;
}
编译
$ javac JNITest.java
$ gcc -I/usr/lib/jvm/java-1.8.0-openjdk-amd64/include/ -fPIC -shared -o libmynative.so test.c
编译报错
在 /usr/lib/jvm/java-1.8.0-openjdk-amd64/include/ 路径下找到jni_md.h头文件,但是其路径是/usr/lib/jvm/java-1.8.0-openjdk-amd64/include/linux/jni_md.h,链接一个过去
sudo ln -s /usr/lib/jvm/java-1.8.0-openjdk-amd64/include/linux/jni_md.h /usr/lib/jvm/java-1.8.0-openjdk-amd64/include/jni_md.h
查看链接情况
链接成功;重新编译ok。
运行
$ export LD_LIBRARY_PATH=.
$ java JNITest
结果如下
关于JNINativeMethod的定义,在jni.h
/*
* used in RegisterNatives to describe native method name, signature,
* and function pointer.
*/
typedef struct {
char *name; /*java 中函数的名字*/
char *signature; /*函数的参数和返回值,参数个数、类型必须对应*/
void *fnPtr; /*C 中函数名字,这是一个函数指针*/
} JNINativeMethod;
2、java传入int 类型的参数到c函数,c函数返回int 类型到java。
java code
public class JNITest {
static {
/*加载*/
System.loadLibrary("mynative");
}
public native static int JavaHello(int a);
public static void main(String[] args) {
/*java c库 函数建立联系*/
/*调用*/
System.out.println( JavaHello(128));
}
}
编译
$ javac JNITest.java
生成头文件
$ javah -jni JNITest
==> 生成 JNITest.h文件,打开如下
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class JNITest */
#ifndef _Included_JNITest
#define _Included_JNITest
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: JNITest
* Method: JavaHello
* Signature: (I)I /*对应C中的JNINativeMethod 中的 Signature 变量*/
*/
JNIEXPORT jint JNICALL Java_JNITest_JavaHello /*C中函数的定义及参数,函数名可以更改,参数个数、类型需要一样*/
(JNIEnv *, jclass, jint);
#ifdef __cplusplus
}
#endif
#endif
因此C code 更改为
#include <stdio.h>
#include <jni.h>
int c_hello(JNIEnv *env, jclass cls, jint a) /*C 中将被 Java 调用的函数*/
{
printf("hello, this is my natvie test, and recive: %d\n", a);
return 256;
}
static const JNINativeMethod methods[] = { /*声明java 和 c 中相关联的函数,和参数*/
{"JavaHello", "(I)I", (void *)c_hello},
};
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *jvm, void *reserved) /*主要功能是注册c函数到java的运行空间,实现真正的java和c之间的关联*/
{ /*库被加载的时候,该函数被调用*/
JNIEnv *env;
jclass cls;
if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4)) /*获取但前java的版本号*/
{
return JNI_ERR;
}
cls = (*env)->FindClass(env, "JNITest"); /*寻找对应的java class,所以这里的名字一定要和java调用者一样*/
if(cls == NULL)
{
return JNI_ERR;
}
/*java c库 函数建立联系*/
if((*env)->RegisterNatives(env, cls, methods, 1) < 0) /*将 JNINativeMethod 数组注册,实现java函数和C函数的挂接,从而可以通过java函数调用c函数 */
return JNI_ERR;
return JNI_VERSION_1_4;
}
验证结果
3、字符串传递
java code
public class JNITest {
static {
/*加载*/
System.loadLibrary("mynative");
}
public native static String JavaHello(String a);
public static void main(String[] args) {
/*java c库 函数建立联系*/
/*调用*/
System.out.println( JavaHello("CCCCCCCCCCCCCCCCCC"));
}
}
生成的头文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class JNITest */
#ifndef _Included_JNITest
#define _Included_JNITest
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: JNITest
* Method: JavaHello
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_JNITest_JavaHello
(JNIEnv *, jclass, jstring);
#ifdef __cplusplus
}
#endif
#endif
C code
#include <stdio.h>
#include <jni.h>
JNIEXPORT jstring JNICALL c_hello(JNIEnv *env, jclass cls, jstring j_str) /*C 中将被 Java 调用的函数*/
{
const jbyte *c_str;
c_str = (*env)->GetStringUTFChars(env, j_str, NULL); /*做字符串的转换,将java 传过来的字符串转换为 c 的字符串*/
if(NULL == c_str)
return NULL;
printf("hello, this is my natvie test, and recive: %s\n", c_str);
return (*env)->NewStringUTF(env, "JAVAJAVAJAVAJAVAJAVA");
}
static const JNINativeMethod methods[] = { /*声明java 和 c 中相关联的函数,和参数*/
{"JavaHello", "(Ljava/lang/String;)Ljava/lang/String;", (void *)c_hello},
};
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *jvm, void *reserved) /*主要功能是注册c函数到java的运行空间,实现真正的java和c之间的关联*/
{ /*库被加载的时候,该函数被调用*/
JNIEnv *env;
jclass cls;
if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4)) /*获取但前java的版本号*/
{
return JNI_ERR;
}
cls = (*env)->FindClass(env, "JNITest"); /*寻找对应的java class,所以这里的名字一定要和java调用者一样*/
if(cls == NULL)
{
return JNI_ERR;
}
/*java c库 函数建立联系*/
if((*env)->RegisterNatives(env, cls, methods, 1) < 0) /*将 JNINativeMethod 数组注册,实现java函数和C函数的挂接,从而可以通过java函数调用c函数 */
return JNI_ERR;
return JNI_VERSION_1_4;
}
运行结果:
以上分享是学习了韦老师课程后的整理与记录。