PS:要转载请注明出处,本人版权所有。

PS: 这个只是基于《我自己》的理解,

如果和你的原则及想法相冲突,请谅解,勿喷。

前置说明

  本文作为本人csdn blog的主站的备份。(BlogID=052)

  本文发布于 2018-01-09 09:13:35,现用MarkDown+图床做备份更新。blog原图已丢失,使用csdn所存的图进行更新。(BlogID=052)

环境说明

  无

前言


  由于最近重新接触了部分Android相关的东西,对一些需要混合编程的手段做了整理,同时也对Java中常见的反射技术进行归纳总结。(本文适合知道JNI和反射是什么鬼的人阅读)(可变参数实现在JNI部分的IoctlGpio方法)

Java JNI


  Java native interface(java本地调用接口)主要是实现C或者C++和java交互。

先来看一张来至于网上的图(如果侵权,请联系我,我会第一时间删除)

  此图说明了一个jvm中(一个进程中)所拥有的资源。而JNI就是用来实现调用本地方法的一种方法。而这些本地方法有两种方式可以被注册到jvm中,分别如下:

JNI之静态注册
public class Operate_Gpio {
public native int IoctlGpio(int cmd, String ...arg);
public native int IoctlGpio(int cmd, int ...arg); //java static code
static {
System.loadLibrary("OperateGpio");
}
}
//call IoctlGpio()
Operate_Gpio op_gpio = new Operate_Gpio();
op_gpio.IoctlGpio(2,1,3);
op_gpio.IoctlGpio(2,"a","b");
extern "C"
JNIEXPORT jint JNICALL
Java_JNI_Operate_1Gpio_IoctlGpio(JNIEnv *env, jobject instance, jint cmd,jobjectArray arg) { jboolean iscopy; switch (cmd) {
case 1: {
jint *arg1 = env->GetIntArrayElements((jintArray) arg, 0); NativeLog(env, instance, 'D', "Test string arg1",
Int_to_String(arg1[0]));
NativeLog(env, instance, 'D', "Test string arg2",
Int_to_String(arg1[1]));
env->ReleaseIntArrayElements((jintArray)arg, arg1, 0);
break;
}
case 2: {
jstring arg3 = (jstring) env->GetObjectArrayElement(arg, 0);
jstring arg4 = (jstring) env->GetObjectArrayElement(arg, 1);
NativeLog(env, instance, 'D', "Test string arg3",
env->GetStringUTFChars(arg3, &iscopy));
NativeLog(env, instance, 'D', "Test string arg4",
env->GetStringUTFChars(arg4, &iscopy));
break;
}
default:{
break;
} }
return 0; }

  说明:通过特定的函数命名方式(包名__类名__函数名)(若以上命名中含有_,将会通过在其后加一位数字方式来标识)来注册。当在java层调用System.loadLibrary,jvm会遍历这个so库的所有合法的方法,并放到本地方法栈,以供使用。

  缺点:

  1. 初次call本地函数时,需要先在jni下去搜索相关的jni函数,然后建立jni函数和native函数关系,导致效率降低
  2. 使用规则复杂,不利于开发(不方便)。
JNI之动态注册
public class Operate_Gpio {
public native int TestGpio();
//java static code
static {
System.loadLibrary("OperateGpio");
}
} Operate_Gpio op_gpio = new Operate_Gpio();
op_gpio.TestGpio();
/**
* Table of methods associated with a single class.
*/
/*
*
* typedef struct {
const char* name;
const char* signature;
void* fnPtr;
} JNINativeMethod;
* */
// 结构体,分别是java层的函数名称,签名,对应的函数指针
static JNINativeMethod gMethods[] = {
{ "TestGpio", "()I", (void*)TestGpio },//绑定
};
static int registerNativeMethods(JNIEnv* env, const char* className,
JNINativeMethod* gMethods, int numMethods)
{
jclass clazz;
clazz = env->FindClass(className);
if (clazz == NULL) {
return JNI_FALSE;
}
if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
return JNI_FALSE;
} return JNI_TRUE;
} JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
{
JNIEnv* env = NULL; if ( vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
return -1;
}
assert(env != NULL); if (!registerNativeMethods(env, JNIREG_CLASS, gMethods,
sizeof(gMethods) / sizeof(gMethods[0])))
return -1;
/* success -- return valid version number */
return JNI_VERSION_1_4;
}

  说明:

  1. JNINativeMethod保存Java Native函数和JNI函数的对应关系
  2. Java层中调用System.loadLibrary加载so库,并调用JNI_OnLoad开始注册
  3. JNI_OnLoad中调用AndroidRuntime::registerNativeMethods
  4. AndroidRuntime::registerNativeMethods中调用 jniRegisterNativeMethods

  注意:这里有个知识叫做java签名,此签名是指的方法的类型标识,也就是一堆类型简写。(写法:(函数参数列表)返回值)

  下列是常用的类型总结(资料来于网上,若有侵权,请联系我,我第一时间删除):

/*

Java方法签名中特殊字符/字母含义
特殊字符 数据类型 特殊说明
V void 一般用于表示方法的返回值
Z boolean
B byte
C char
S short
I int
J long
F float
D double
[ 数组 以[开头,配合其他的特殊字符,表示对应数据类型的数组,几个[表示几维数组
L全类名; 引用类型 以L开头、;结尾,中间是引用类型的全类名 */

Java Reflect


  程序运行时获取类的属性,也可调用类的方法。可灵活的方便构建出各种复杂的逻辑结构。

C或者C++层反射

int static NativeLog(JNIEnv *env, jobject instance ,char type, std::string tag, std::string msg){ jclass clazz = env->FindClass("android/util/Log") ;
jmethodID jmth_id;
switch (type){ case 'V':
jmth_id = env->GetStaticMethodID(clazz, "v", "(Ljava/lang/String;Ljava/lang/String;)I");
break;
case 'D':
jmth_id = env->GetStaticMethodID(clazz, "d", "(Ljava/lang/String;Ljava/lang/String;)I");
break;
case 'I':
jmth_id = env->GetStaticMethodID(clazz, "i", "(Ljava/lang/String;Ljava/lang/String;)I");
break;
case 'W':
jmth_id = env->GetStaticMethodID(clazz, "w", "(Ljava/lang/String;Ljava/lang/String;)I");
break;
case 'E':
jmth_id = env->GetStaticMethodID(clazz, "e", "(Ljava/lang/String;Ljava/lang/String;)I");
break;
default:
break;
} return env->CallStaticIntMethod(clazz, jmth_id, env->NewStringUTF(tag.c_str()), env->NewStringUTF(msg.c_str()));
} extern "C"
JNIEXPORT jint JNICALL
Java_JNI_Operate_1Gpio_OpenGpio(JNIEnv * env, jobject obj){
//open devices ... ...
NativeLog(env, obj, 'D', "Test", "Reflect test.");
return 0;
}
public class Operate_Gpio {

    public native int OpenGpio();

    // Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("OperateGpio");
}
} Operate_Gpio op_gpio = new Operate_Gpio();
op_gpio.OpenGpio();
JAVA层反射
        try {
Class clazz = Class.forName("android.util.Log");
Method method = clazz.getDeclaredMethod("d", String.class, String.class);
method.invoke(null,"Test","Fuck");//调用静态函数
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}

  所有结果的最终效果如图:

后记


  无

参考文献


打赏、订阅、收藏、丢香蕉、硬币,请关注公众号(攻城狮的搬砖之路)

PS: 请尊重原创,不喜勿喷。

PS: 要转载请注明出处,本人版权所有。

PS: 有问题请留言,看到后我会第一时间回复。

Android JNI静态和动态注册 、Java Reflect(C或C++层反射和JAVA层反射)、Java 可变参数(JNI实现)的更多相关文章

  1. Android深入理解JNI(一)JNI原理与静态、动态注册

    前言 JNI不仅仅在NDK开发中应用,它更是Android系统中Java与Native交互的桥梁,不理解JNI的话,你就只能停留在Java Framework层.这一个系列我们来一起深入学习JNI. ...

  2. JNI原理与静态、动态注册

    前言 JNI不仅仅在NDK开发中应用,它更是Android系统中Java与Native交互的桥梁,不理解JNI的话,你就只能停留在Java Framework层.这一个系列我们来一起深入学习JNI. ...

  3. ndk学习20: jni之OnLoad动态注册函数

    一.原理 当在系统中调用System.loadLibrary函数时,该函数会找到对应的动态库, 然后首先试图找到"JNI_OnLoad"函数,如果该函数存在,则调用它 JNI_On ...

  4. Java基础知识强化之集合框架笔记32:集合之可变参数的概述和使用

    1. 可变参数的概述和使用: (1)可变参数:定义方法的时候不知道该定义多少个参数(2)格式:     修饰符  返回值类型  方法名(数据类型… 变量名){   }  注意: 这里的变量其实是一个数 ...

  5. Android(java)学习笔记173:BroadcastReceiver之 静态注册 和 动态注册

    1. 广播接受者>什么是广播.收音机.电台:对外发送信号.收音机:接收电台的信号. >在android系统里面,系统有很多重要的事件: 电池电量低,插入充电器,sd卡被移除,有电话打出去, ...

  6. Android(java)学习笔记116:BroadcastReceiver之 静态注册 和 动态注册

    1. 广播接受者>什么是广播.收音机.电台:对外发送信号.收音机:接收电台的信号. >在android系统里面,系统有很多重要的事件: 电池电量低,插入充电器,sd卡被移除,有电话打出去, ...

  7. Android中BroadcastReceiver的两种注册方式(静态和动态)详解

    今天我们一起来探讨下安卓中BroadcastReceiver组件以及详细分析下它的两种注册方式. BroadcastReceiver也就是"广播接收者"的意思,顾名思义,它就是用来 ...

  8. JNI静态注册与动态注册详解

    JNI注册,是指将java层方法(native关键字修饰的)和C层方法对应起来,以实现java层代码调用c层代码的目的.JNI注册分为静态注册和动态注册两种,静态注册是通过固定格式方法名进行关联,动态 ...

  9. BroadcastReceiver的两种注册方式之------动态注册

    activity_main.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android&qu ...

  10. Java 中可变参数

    可变参数 Java 中可变参数 现在需要编写一个求和的功能,但是不知道有几个参数,在调用的时候才知道有几个参数,请问这如何实现呢? Java 给我们提供了一个 JDK 1.5 的新特性---可变参数 ...

随机推荐

  1. Mac基于VMware安装CentOS

    流程偏长,下一步根本点不完: 01 首先,明确下两款软件的版本信息: VMware是[VMware-Fusion-13.5.0] CentOS是[CentOS-7-x86_64-Minimal-190 ...

  2. 一句话总结Docker与K8S的关系

    一句话总结:Docker只是容器的一种,它面向的是单体,K8S可以管理多种容器,它面向的是集群,Docker可以作为一种容器方案被K8S管理.下文继续具体介绍. 1.容器的核心概念 介绍这几个核心概念 ...

  3. 虚拟机 VMware Workstation 16 PRO 的网络配置

    原文地址: https://blog.csdn.net/weixin_41905135/article/details/123858658 (一)VMware编辑虚拟网络 ​ 默认情况下,VMware ...

  4. Pandas数据合并

    目录 1) 在单个键上进行合并操作 2) 在多个键上进行合并操作 使用how参数合并 1) left join 2) right join 3) outer join(并集) 4) inner joi ...

  5. 2023年多校联训NOIP层测试2

    2023年多校联训NOIP层测试2 爆零了 T1 HDU 4786 Fibonacci Tree \(0pts\) @wangyunbiao: 不可以,总司令 我:不,可以,总司令 @wangyunb ...

  6. v-html可能导致的问题

    v-html可能导致的问题 Vue中的v-html指令用以更新元素的innerHTML,其内容按普通HTML插入,不会作为Vue模板进行编译,如果试图使用v-html组合模板,可以重新考虑是否通过使用 ...

  7. ADVMP 三代壳(vmp加固)原理分析(加壳流程)

    开源项目地址 https://github.com/chago/ADVMP vmp 加固可以说时各大加固厂商的拳头产品了,这个开源项目虽然不是十分完善,让我们可以一览vmp加固的原理,是十分好的学习资 ...

  8. 项目实战:Qt监测操作系统物理网卡通断v1.1.0(支持windows、linux、国产麒麟系统)

    需求   使用Qt软件开发一个检测网卡的功能.  兼容windows.linux,国产麒麟系统(同为linux) Demo   windows上运行:       国产麒麟操作上运行:       功 ...

  9. 02-Redis系列之-架构和高级API的使用

    通用部分 通用命令 # 1-keys # 打印出所有key keys * # 打印出所有以n开头的key keys n* # 打印出所有以nam开头,第四个字母是a到z的范围 keys nam[a-z ...

  10. .NET Core 引发的异常:“sqlsugar.sqlsugarexception” 位于 system.private.corelib.dll 中

    运行一个.NET Core 项目 报错:引发的异常:"sqlsugar.sqlsugarexception" 位于 system.private.corelib.dll 中 . 我 ...