JNI的第2种写法:本地方法注册
声明:迁移自本人CSDN博客https://blog.csdn.net/u013365635
孔乙己说,茴香豆的茴有四种写法,今天谈谈JNI的第2种写法:本地方法注册。
这种写法的好处是不需要使用javah生成一个C++头文件,也不必使用javah自动生成的长长的C++函数名,往往在native函数很多的情况下,扩展比较灵活。
之前的笔者写的文章中介绍的是函数名映射的方法,今天介绍的是采用注册本地方法的方式 。本质都是建立起Java层native函数和C层函数的映射关系。
C++代码部分做了一些额外的测试操作,这些测试操作意在表明Java堆和C本地堆之间的关系。
测试类
package com.testjnitype2;
public class TestJNIType2
{
private static NativeUtils nativeUtils = new NativeUtils();
static
{
System.load("D:\\test\\src\\com\\testjnitype2\\lib_testjni_Type2_amd64.dll");
}
public static void main(String[] args)
{
byte[] dataSharedByJavaC = new byte[10];
System.out.println("JNIType2 before-->dataSharedByJavaC=" + dataSharedByJavaC);
for (int i = 0; i < 10; i++)
{
System.out.print(dataSharedByJavaC[i] + " ");
}
System.out.println("\n----------");
nativeUtils.tranferBytes(dataSharedByJavaC);
System.out.println("JNIType2 after-->dataSharedByJavaC=" + dataSharedByJavaC);
for (int i = 0; i < 10; i++)
{
System.out.print(dataSharedByJavaC[i] + " ");
}
}
}
java native方法定义类
package com.testjnitype2;
public class NativeUtils
{
public native void tranferBytes(byte[] dataSharedByJavaC);
}
C++实现类
#include "jni.h"
#include "stdio.h"
static const char *classPath = "com/testjnitype2/NativeUtils";
int FAILURE = -1;
int SUCESS = 0;
JNIEXPORT void JNICALL tranfer_bytes(JNIEnv *jniEnv, jobject obj, jbyteArray dataSharedByJavaC);
//step1-1:建立java方法与native 方法的映射关系
//JNINativeMethod定义在jni.h中,定义如下
/**
typedef struct {
char *name;
char *signature;
void *fnPtr;
} JNINativeMethod;
*/
static const JNINativeMethod methods[] =
{
/*
tranferBytes为java层定义的方法,tranfer_bytes为native层定义的方法,此处就不需要写成Java_com_testjnitype2_NativeUtils_tranferBytes这种格式了
*/
{"tranferBytes", "([B)V", (void*)tranfer_bytes}
};
//step 1-2:实现与java方法映射到的本地方法
JNIEXPORT void JNICALL tranfer_bytes(JNIEnv *jniEnv, jobject obj, jbyteArray dataSharedByJavaC)
{
printf("\n----------");
//data在native层的地址
printf("\ndataSharedByJavaC addr = %x, dataSharedByJavaC and dataSharedByJavaC addr transfered from java parsed by native is random:\n", dataSharedByJavaC);
for (int i=0; i<10; i++)
{
printf("%d ", dataSharedByJavaC[i]);
}
//data在native层解析后指向java data后的地址
jbyte* p = jniEnv->GetByteArrayElements(dataSharedByJavaC, NULL);
printf("\n----------");
printf("\np addr = %x, make native p point to java heap, now native data pointed by p is definitized, in other wolds, it's java heap data:\n", p);
for (int i=0; i<10; i++)
{
printf("%d ", p[i]);
}
//重新赋值,也就是更改Java heap中的数据
for (int i = 0; i < 10; i++)
{
p[i] = i * i + 1;
}
jniEnv->ReleaseByteArrayElements(dataSharedByJavaC, p, 0);
return;
}
//step2:在jvm中注册映射关系
int registerNativeMethods(JNIEnv *env, const char *classPath)
{
printf("begin register native methods");
jclass clazz = env->FindClass(classPath);
if (!clazz)
{
return FAILURE;
}
if (env->RegisterNatives(clazz, methods, sizeof(methods)/sizeof(JNINativeMethod)) != JNI_OK)
{
return FAILURE;
}
return SUCESS;
}
/**
step3:实现jni.h中声明的方法JNI_OnLoad,并调用step 2中的注册方法
该方法在程序启动时,Java加载本地库的时被调用,比如System.load("xxx");
*/
JNIEXPORT jint JNI_OnLoad(JavaVM *jvm, void* reserved)
{
printf("JNI OnLoad");
JNIEnv *env;
if (jvm->GetEnv((void**)&env, JNI_VERSION_1_8) != JNI_OK)
{
printf("get env error");
return -1;
}
registerNativeMethods(env, classPath);
return JNI_VERSION_1_8;
}
/**
实现jni.h中声明的方法
*/
JNIEXPORT void JNI_OnUnload(JavaVM* jvm, void* reserved)
{
JNIEnv *env;
if (jvm->GetEnv((void**)&env, JNI_VERSION_1_8) != JNI_OK)
{
printf("get env error");
}
}
C代码编译方法
d:\VS2010\Microsoft Visual Studio 10.0\VC>cl /LD D:\test\src\com\testjnitype2\testjnitype2.cpp -o D:\test\src\com\testjnitype2\lib_testjni_Type2_amd64.dll
编译完后目录大概如下图。
执行结果如下
JNIType2 before-->dataSharedByJavaC=[B@78308db1
0 0 0 0 0 0 0 0 0 0
----------
JNIType2 after-->dataSharedByJavaC=[B@78308db1
1 2 5 10 17 26 37 50 65 82
----------
JNI OnLoad
----------
begin register native methods
----------
dataSharedByJavaC addr = 2c5f470, dataSharedByJavaC and dataSharedByJavaC addr transfered from java parsed by native is random:
240 96 213 106 7 0 0 0 88 89
----------
p addr = 1dd95e70, make native p point to java heap, now native data pointed by p is definitized, in other wolds, it's java heap data:
0 0 0 0 0 0 0 0 0 0
执行结果暗含了很多信息,比如,输出的顺序、打印的数组值为什么会是上面的样子?这个会做个专题进行讨论。
再说说jni的使用方法吧,其实,本地方法注册法和函数名映射法可以混合使用的。
顺便说一句,netty集成平台动态库的方法就是用的这种。
以上。
JNI的第2种写法:本地方法注册的更多相关文章
- 字符设备驱动另一种写法—mmap方法操作LED
最近在看韦老师的视频,讲解了很多种字符设备的驱动写法.经过自己的研究之后,我发现还有另外一种写法,直接在应用层操作,省去了内核中的地址映射部分,使得用户可以在应用层直接操作LED. mm ...
- JNI的第1种写法 及 JNI通过形参修改Java数据
声明:迁移自本人CSDN博客https://blog.csdn.net/u013365635 目的:通过形参在Java 和C之间传递数据,尤其是大块的媒体数据 优点:避免通过返回值返回一个巨大的数据块 ...
- 使用JNA替代JNI调用本地方法
JNA全称是Java Native Access,是Sun推出的一种调用本地方法技术,比起它的同门师兄JNI,JNA大大简化了调用本地方法的过程,使用也比较方便, JNA是在JNI的基础上完善的,用青 ...
- Effective Java 第三版——66. 明智谨慎地使用本地方法
Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...
- javascript中面向对象的5种写法
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 鼠标放上时显示隐藏的div或者其他代码的“jquery”的三种写法和“JavaScript”的一种写法
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Android Studio NDK JNI动态注册本地方法
概述 可能大家觉得javah生成的函数名又臭又长,不太好看.这里可以提供另外一种方法来动态注册c++函数,让其根Java中的native方法关联起来. 实现 这里通过JNIEnv的Resisterna ...
- Android调用JNI本地方法经过有点改变
方法注册好后要经过哪些路 Android一个异常捕获项目 https://github.com/xroche/coffeecatch coffeecatch CoffeeCatch, a tiny n ...
- java 本地方法(JNI)
最近搞了一个调用第三方so库做登录认证的任务,以前对JNI没什么概念,最近学习了 <java核心技术> 本地方法 一章,把自己写的一些例子记录一下. 自己C语言真是渣渣,所以所有的例子都在 ...
随机推荐
- 无法启动APK安装也,报异常FileUriExposedException
无法打开APK安装页,报异常FileUriExposedException, https://juejin.im/entry/58e4643db123db15eb79a902
- flink笔记(三) flink架构及运行方式
架构图 Job Managers, Task Managers, Clients JobManager(Master) 用于协调分布式执行.它们用来调度task,协调检查点,协调失败时恢复等. Fli ...
- Node.js NPM 作用
章节 Node.js NPM 介绍 Node.js NPM 作用 Node.js NPM 包(Package) Node.js NPM 管理包 Node.js NPM Package.json NPM ...
- jupiter的@TempDir 等不生效
jupiter与junit是 完全独立的测试组件,要严防在测试中将二者混用.最好在依赖引入jupiter 时 就将junit的依赖干掉,以防在写测试用例时将二者混用.不会报错,但是会导致 jupite ...
- 批量go get 代码
批量 go get 代码 Go
- UVA - 11400 Lighting System Design(照明系统设计)(dp)
题意:共有n种(n<=1000)种灯泡,每种灯泡用4个数值表示.电压V(V<=132000),电源费用K(K<=1000),每个灯泡的费用C(C<=10)和所需灯泡的数量L(1 ...
- 知乎live - 三年从前端小工到架构
王利华 刚毕业 在高德 携程 淘宝 0-3年如何发展 1 技能和能力的区别 css js 抽象 切勿好高骛远 要重视基础 2 人和人的差距是什么 注意个人品牌 提高 ...
- jQuery元素的左右移动
1.下载jQuery,并导入:https://blog.csdn.net/weixin_44718300/article/details/88746796 2.代码实现: <!DOCTYPE h ...
- consul配置
参考:https://blog.csdn.net/achenyuan/article/details/80389410 gcp: consul安装目录:/usr/local/bin/consul co ...
- 利用京东云Serverless服务快速构建5G时代的IoT应用
10月31日,在2019年中国国际信息通信展览会上,工信部宣布:5G商用正式启动.5G商用时代来了! 5G的商用,使得数据传输速度.响应速度.连接数据.数据传输量.传输可靠性等方面都有了显著的提升,这 ...