Android JNI代码语法解释

JNI中的JNIEXPORT、JNIIMPORT和JNICALL

两个关键字的定义都可以在jni_md.h下找到

均用于定义与平台相关的宏

用于标识函数用途

  • JNIEXPORT:(实则为C++规则)放置在函数、变量或对象的声明前面,指示编译器将其导出为动态链接库的一部分。这使得其他程序可以通过在运行时加载动态链接库并使用导出的函数、变量或对象
  • JNIIMPORT:(实则为C++规则)放置在函数、变量或对象的声明前面,指示编译器将其标记为从动态链接库中导入的符号
  • JNICALL:(实则为C++规则)一种标准的函数调用约定,也被称为 “标准调用”;具有以下性质:
    函数的参数按照从右到左的顺序依次入栈。这意味着最右边的参数首先被压入栈中。
    调用方清理栈上的参数。这意味着在函数调用结束后,由调用方负责从栈上移除函数的参数。
    函数的返回值通常存储在 EAX 寄存器中
//Windows下的定义
#define JNIEXPORT __declspec(dllexport)
#define JNIIMPORT __declspec(dllimport)
#define JNICALL __stacall

//Linux下的定义(实际是空定义)
#define JNIEXPORT
#define JNIIMPORT
#define JNICALL

JVM如何查找native方法

①按照JNI规范的命名规则

即根据JNI所约定的命名规则来指定函数的命名,具体规则如下:Java_类全路径_方法名

JNIEXPORT jstring JNICALL Java_com_kqli_jni_JniTest_getStringFromC(JNIEnv *env, jclass jclass);
JNIEXPORT jstring JNICALL Jave_com_test_jni_HelloWord_func(JNIEnv* env, jclass class, jstring str);
  • 第一个jstring为返回值(string类型)
  • 函数名中com_kqli_jni_JniTest_getStringFromC,代表Java类com_kqli_jni_JniTest,getStringFromC代表具体的函数名称
    JNIEnv,指向JVM函数表的指针
  • jclass,调用Java中native方法的实例对象

②调用JNI提供的RegsterNatives函数,将本地函数注册到JVM中

//函数原型
jint RegisterNatives(JNIEnv *env, jclass clazz, const JNINativeMethod *methods, jint nMethods);
  • clazz:声明native方法的类
  • methods:JNINativeMethod结构的数组
typedef struct {
    char *name;	//java方法名称
    char *signature;//java方法签名
    void *fnPtr;//c/c++的函数指针
} JNINativeMethod;
  • nMethods:指定methods数组中的本地方法数,通常写法为
nMethods = sizeof(methods) / sizeof(JNINativeMethod);

示例代码

java

package com.test.jni;

public class A{
	static{
		System.loadLibrary("A");	
	}
	
	public static native int a(String str);
	public static native boolean b();
	public static native int c(Object obj);
	
	public static void main(String[] args){
		......
	}
}

native

jint a(JNIEnv *env ,jclass class, jstring str){
   ....
}

jboolean b(JNIEnv *env ,jclass class){
   ....
}

jint c(JNIEnv *env ,jclass class, jobject obj){
   ....
}

static JNINativeMethod method_table[] = 
{
	{"a", "(Ljava/lang/String;)I", (void *)a},
	{"b", "()Z", (void *)b},
	{"c", "(Ljava/lang/Object;)I", (void *)c},
};

jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    ......
    jclass clz = env ->FindClass(JNIREG_CLASS);
    env ->RegisterNatives(clz, method_table, sizeof(method_table) / sizeof(JNINativeMethod));
    ......
}

JNI数据类型

在这里插入图片描述

类: 例如String的签名为Ljava/lang/String; 注意: 包名和类名用/隔开, 结尾有一个;
数组:用[表示数组签名, 例如int[]的签名为[I

JNI字符串的处理

①获取字符串

JNI通过jstring来处理字符串数据,但是jstring是指向JVM内部的字符串,和C风格的字符串类型char * 不同,因此必须使用合适的JNI函数来访问JVM内部的字符串。
因为Java默认使用unicode编码,而C/C++默认使用UTF编码,所以要注意进行编码转换。

const char* GetStringUTFChars(jstring str, jbbolean *isCopy);
  • str为需要获取的字符串
  • isCopy取值JNI_TRUE和JNI_FALSE,一般填NULL即可
  • JNI_TRUE:返回JVM内部源字符串的拷贝,并为新产生的字符串分配内存空间
  • JNI_FALSE:返回JVM内部源字符串的指针,并可以指针修改源字符串的内容

②释放字符串

通过GetStringUTFChars获取到字符串并返回的为源字符串拷贝后,在使用完毕要记得释放内存。

void ReleaseStringUTFChars(jstring str, const char* utf);
  • str为需要释放的字符串指针
  • utf为字节编码

③创建字符串

jstring NewStringUTF(const char * bytes);
  • bytes为C/C++的字符串数据源

④其他字符串处理API

  • GetStringChars、ReleaseStringChars:用于获取/释放Unicode格式的字符串
  • GetStringUTFLength、GetStringLength:用于获取UTF-8/Unicode格式的字符串长度
  • GetStringCritical、ReleaseStringCritical:用于直接返回/释放源字符串的指针,获取这个指针会导致暂停GC线程,如果GC线程暂停时又被其他线程触发GC的话,会出现系统死锁的阻塞调用
  • GetStringUTFRegion、GetStringRegion:用于获取UTF-8/Unicode格式字符指定范围内的内容,并会将源字符串复制到一个预先分配的缓冲区内
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android JNI学习路线可以按照以下步骤进行: 1. 了解JNI的基本概念和作用:JNI(Java Native Interface)是Java提供的一种机制,用于实现Java与其他编程语言(如C、C++)之间的交互。它允许在Java代码中调用本地代码(Native Code),并且可以在本地代码中调用Java代码。 2. 学习JNI的基本语法和规则:JNI使用一组特定的函数和数据类型来实现Java与本地代码之间的交互。你需要学习如何声明本地方法、如何在Java代码中调用本地方法、如何在本地代码中调用Java方法等。 3. 学习JNI的数据类型映射:JNI提供了一套数据类型映射规则,用于将Java数据类型映射到本地代码中的数据类型。你需要学习如何处理基本数据类型、对象类型、数组类型等。 4. 学习JNI的异常处理:在JNI中,Java代码和本地代码之间的异常处理是非常重要的。你需要学习如何在本地代码中抛出异常、如何在Java代码中捕获异常等。 5. 学习JNI的线程处理:JNI允许在本地代码中创建和操作线程。你需要学习如何创建和销毁线程、如何在线程之间进行通信等。 6. 学习JNI的性能优化:JNI涉及到Java代码和本地代码之间的频繁切换,因此性能优化是非常重要的。你需要学习如何减少JNI调用的次数、如何避免不必要的数据拷贝等。 7. 学习JNI的调试和测试:在开发JNI程序时,调试和测试是非常重要的。你需要学习如何使用调试器调试本地代码、如何进行单元测试等。 8. 学习JNI的进阶主题:一旦掌握了基本的JNI知识,你可以进一步学习JNI的进阶主题,如JNI与Java虚拟机的交互、JNI与动态链接库的交互、JNI与多线程的交互等。 总结起来,Android JNI学习路线包括了基本概念、基本语法、数据类型映射、异常处理、线程处理、性能优化、调试和测试以及进阶主题等内容。通过系统地学习这些知识,你将能够更好地理解和应用JNI技术。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值