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语言真是渣渣,所以所有的例子都在 ...
随机推荐
- Oracle-SQL 小题
1.查询姓名中不包含C和c的员工信息 ; ①字符函数 instr(input,char,m,n) 的用法:返回在字符值中查找字符串char的数字位置.参数m作为查找的开始,参数n代表第n次发现.m和n ...
- Vulkan SDK 之 Shaders
Compiling GLSL Shaders into SPIR-V 1.SPIR-V 是vulkan的底层shader语言.GLSL可以通过相关接口转换为SPIR-V. Creating Vulka ...
- CNN经典模型VGG
VGG是一个很经典的CNN模型,接触深度学习的人大概都有所耳闻.VGG在2014年被提出并拿来参加ImageNet挑战赛,最终实现了92.3%的正确率,得到了当年的亚军.虽然多年过去,又有很多新模型被 ...
- 六十二、SAP中的字符串运算符与文本拼接
一.代码如下 二.输出效果如下
- 133-PHP子类无法重写父类private同名函数
<?php class father{ //定义father类 //定义protected成员方法 protected function cook(){ return 'protected co ...
- 干货分享|留学Essay怎么写?
留学生活其实就是分割成一个个deadline,留学就是赶完一个又一个deadline.朋友同学的革命情感源自赶一个个deadline时候的不离不弃,相知相守,无数个夜里大家群里打卡,你今天Essay写 ...
- check Linux文件夹个数
(ls -l|grep "^-"| wc -l)查看某个文件夹下文件的个数.(ls -lR|grep "^-"| wc -l)查看某个文件夹下文件的个数,包括子 ...
- 编程入门-Eclipse基本使用
编程入门-Eclipse基本使用 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.设置Eclipse的基本参数 1>.修改Eclipse默认的文件编码为"utf- ...
- c\c++ 中字符串分割,并且转换为整形数据
在项目开发中,经常使用到字符串分割, 并且将其转换为整形(比如IP的分割获取,MAC地址的分割获取等),代码如下: #ifndef _UNICODE void StrToIntData( char * ...
- 关于spring cloud “Finchley.RC2”版本在spring cloud config中的ArrayIndexOutOfBoundsException
原文 https://www.cnblogs.com/Little-tree/p/9166382.html 在学spring cloud config的时候遇到一个ArrayIndexOutOfBou ...