java jni 参数_java JNI简介

JNI的接口函数和指针

native代码想要访问 java虚拟机需要调用JNI方法,而获取JNI方法则通过 JNI interface Pointer。它实际指向的就是一个都是指针的数组,每个指针指向的都是一个接口函数

f406792dcc9aa061e175afca54f8a7d7.png

这样做的优势:

JNI 命名和native code书写分开,避免硬编码

JNI interface Pointer 只在当前线程有效,即native 方法不能在线程之间传递(不同线程的指针可能不一

样),VM保证同一个线程中调用多次JNI interface Pointer是同一个

编译

JAVA VM支持多线程,native 方法在编译的时候需要加上对应的参数,如 gcc加上 -D_REENTRANT或者-D_POSIX_C_SOURCE

加载

代码如下

package pkg;

class Cls {

native double f(int i, String s);

static {

System.loadLibrary(“pkg_Cls”); //名字可以随便定义

}

}

对于不同的系统,打包的后缀名会有不同,solaris系统一般是libpkg_Cls.so(使用的时候则是直接用的pkg_Cls)Win32的系统则是pkg_Cls.dll

连接

如果当前系统不支持动态连接,所有的Native方法必须预先和VM建立连接,通过System.loadLibrary是无法自动加载。如果要静态连接可以使用 JNI的函数 RegisterNatives

静态连接需要把所有的library复制到可执行的映像中;动态连接是把共享的library的名字放在一个可执行的映像中,当映像运行的时候才去连接

Native方法名

生成规则:Java_ 作为前缀,类的全路径名,用 “_” 分隔每一个目录名,再加上 方法名,如果是重载的方法,则会添加 “__”和

方法签名,比如: 全路径是:com.study.jnilearn.HelloWorld,生成的方法是 Java_com_study_jnilearn_HelloWorld_sayHello:

查找规则:VM查找native library里面的方法名,首先查找短的名字,即方法名没有参数签名;然后查找有参数签名的方法;长方法名只有在native方法重载了另一个native方法的时候需要

方法签名

方法签名的格式为:(形参参数类型列表)返回值。

形参参数列表中,引用类型以L开头,后面紧跟类的全路径名(需将.全部替换成/),以分号结尾

比如:long f(int n,String s,int[] arr); 对应的Native方法签名是 (ILjava/lang/String;[I)J.

各种类型签名对比

c2df7fcc237736a318956377cba4a1fb.png

Native的方法参数

第一个参数是JNI Interface pointer(类型是 JNIEnv),如果是静态native方法,第二个参数则是对应java class的引用,非静态的native则对应的是 对象的引用,其它的参数对应的是java方法的参数

JNI的Hello world实现

创建自己的Hello world文件,在其中使用Native方法

public class HelloWorld {

public static native String sayHello(String name);

public static void main(String[] args) {

String text = sayHello("paxi");

System.out.println(text);

}

static{

System.loadLibrary("HelloWorld");

}

}

用javac编译HelloWorld.java文件

用javah编译产生头文件 HelloWorld.h

命令为 javah -jni -d ./jni HelloWorld;-d:将生成的文件放到jni目录下

生成结果如下:

/* DO NOT EDIT THIS FILE - it is machine generated */

#include

/* Header for class HelloWorld */

#ifndef _Included_HelloWorld

#define _Included_HelloWorld

#ifdef __cplusplus

extern "C" {

#endif

/*

* Class: HelloWorld

* Method: sayHello

* Signature: (Ljava/lang/String;)Ljava/lang/String;

*/

JNIEXPORT jstring JNICALL Java_HelloWorld_sayHello

(JNIEnv *, jclass, jstring);

#ifdef __cplusplus

}

#endif

#endif

用C实现HelloWorld.h中的函数

HelloWorld.c:

#include "HelloWorld.h"

#ifdef __cplusplus

extern "C"

{

#endif

/*

* Class: HelloWorld

* Method: sayHello

* Signature: (Ljava/lang/String;)Ljava/lang/String;

*/

JNIEXPORT jstring JNICALL Java_HelloWorld_sayHello

(JNIEnv *env, jclass cls, jstring j_str){

const char *c_str = NULL;

char buff[128] = {0};

c_str = (*env)->GetStringUTFChars(env,j_str,NULL);

if (c_str == NULL)

{

printf("out of memory\n");

return NULL;

}

printf("Java Str:%s\n", c_str);

sprintf(buff,"hello %s",c_str);

(*env)->ReleaseStringUTFChars(env,j_str,c_str);

return (*env)->NewStringUTF(env,buff);

}

#ifdef __cplusplus

}

#endif

编译C的代码生成native文件

mac下命令为

gcc -dynamiclib -o extensions/libHelloWorld.jnilib jni/HelloWorld.c -framework JavaVM -I/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/include -I/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/include/darwin

* -dynamiclib:表示生成动态链接库

* -o:指定动态链接库编译后生成的路径以及文件名

* -framwork JavaVM -I:编译JNI需要用到的JVM头文件(jni.h)

执行java程序,指定动态链接库

命令为 java -Djava.library.path=动态链接的目录 Helloworld

java Str:paxi

hello paxi

附录

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值