原帖地址:http://blog.csdn.net/qiuxiaolong007/article/details/7860610

除了使用传统方法实现JNI外,也可以使用RegisterNatives实现JNI。和传统方法相比,使用RegisterNatives的好处有三点: 1、C++中函数命名自由,不必像javah自动生成的函数声明那样,拘泥特定的命名方式; 2、效率高。传统方式下,Java类call本地函数时,通常是依靠VM去动态寻找.so中的本地函数(因此它们才需要特定规则的命名格式),而使用RegisterNatives将本地函数向VM进行登记,可以让其更有效率的找到函数; 3、运行时动态调整本地函数与Java函数值之间的映射关系,只需要多次call RegisterNatives()方法,并传入不同的映射表参数即可。 为了使用RegisterNatives,我们需要了解JNI_OnLoad和JNI_OnUnload函数。JNI_OnLoad()函数在VM执行System.loadLibrary(xxx)函数时被调用,它有两个重要的作用:

  • 指定JNI版本:告诉VM该组件使用那一个JNI版本(若未提供JNI_OnLoad()函数,VM会默认该使用最老的JNI 1.1版),如果要使用新版本的JNI,例如JNI 1.4版,则必须由JNI_OnLoad()函数返回常量JNI_VERSION_1_4(该常量定义在jni.h中) 来告知VM。
  • 初始化设定,当VM执行到System.loadLibrary()函数时,会立即先呼叫JNI_OnLoad()方法,因此在该方法中进行各种资源的初始化操作最为恰当,RegisterNatives也在这里进行。

JNI_OnUnload()当VM释放该组件时被调用,JNI_OnUnload()函数的作用与JNI_OnLoad()对应,因此在该方法中进行善后清理,资源释放的动作最为合适。

Java代码和使用哪种方式实现JNI无关,如下所示:

class MyJavaClass
{
public int iValue;
public void Squa(){iValue = iValue*iValue;}
}
public class RegisterNativesTest
{
static{
System.load("/home/zmh/workspace/RegisterNativesTest/lib/libCallClass.so");
}
public static void main(String[] args)
{
RegisterNativesTest app = new RegisterNativesTest();
MyJavaClass obj = new MyJavaClass();
obj.iValue = ;
System.out.println("Before callCustomClass: " + obj.iValue);
app.callCustomClass(obj);
System.out.println("After callCustomClass: " + obj.iValue);
}
private native void callCustomClass(MyJavaClass obj);
}

C++的代码可以分为两部分:实现callCustomClass方法和注册callCustomClass。
实现callCustomClass方法的代码如下:

void callCustomClass(JNIEnv* env, jobject, jobject obj)
{
jclass cls = env->GetObjectClass(obj);
jfieldID fid = env->GetFieldID(cls, "iValue", "I");
jmethodID mid = env->GetMethodID(cls, "Squa", "()V");
int value = env->GetIntField(obj, fid);
printf("Native: %d\n", value);
env->SetIntField(obj, fid, );
env->CallVoidMethod(obj, mid);
value = env->GetIntField(obj, fid);
printf("Native:%d\n", value);
}

C++函数内忽略this指针,他所接收的jobject是“Java程序代码传递过来的Java object reference“在原生端的形式,在C++中对jobject的改变在java中也是有效的。如果想要访问Java数据成员和函数,得先使用GetFieldID或GetMethodID分别获取数据成员和函数的识别码,这两个函数的参数依次为1)class object;2)包含元素名称的字符串;3)表示类型的字符串。
注册callCustomClass在JNI_OnLoad中进行,代码如下:

static JNINativeMethod s_methods[] = {
{"callCustomClass", "(LMyJavaClass;)V", (void*)callCustomClass},
}; int JNI_OnLoad(JavaVM* vm, void* reserved)
{
JNIEnv* env = NULL;
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK)
{
return JNI_ERR;
} jclass cls = env->FindClass("LRegisterNativesTest;");
if (cls == NULL)
{
return JNI_ERR;
} int len = sizeof(s_methods) / sizeof(s_methods[]);
if (env->RegisterNatives(cls, s_methods, len) < )
{
return JNI_ERR;
} return JNI_VERSION_1_4;
}

在C++和Java中创建关联的是JNINativeMethod,它在jni.h中定义:

/*
* used in RegisterNatives to describe native method name, signature,
* and function pointer.
*/
typedef struct {
char *name;
char *signature;
void *fnPtr;
} JNINativeMethod;

name是java中定义的native函数的名字,fnPtr是函数指针,也就是C++中java native函数的实现。signature是java native函数的签名,可以认为是参数和返回值。比如(LMyJavaClass;)V,表示函数的参数是LMyJavaClass,返回值是void。对于基本类型,对应关系如下:

字符     Java类型     C/C++类型
V void void
Z jboolean boolean
I jint int
J jlong long
D jdouble double
F jfloat float
B jbyte byte
C jchar char
S jshort short

数组则以"["开始,用两个字符表示,比如int数组表示为[I,以此类推。
如果参数是Java类,则以"L"开头,以";"结尾,中间是用"/"隔开包及类名,例如Ljava/lang/String;,而其对应的C++函数的参数为jobject,一个例外是String类,它对应C++类型jstring。

实现JNI的另一种方法:使用RegisterNatives方法传递和使用Java自定义类 (转)的更多相关文章

  1. JNI的第2种写法:本地方法注册

    声明:迁移自本人CSDN博客https://blog.csdn.net/u013365635 孔乙己说,茴香豆的茴有四种写法,今天谈谈JNI的第2种写法:本地方法注册. 这种写法的好处是不需要使用ja ...

  2. javascript四种类型识别的方法

    × 目录 [1]typeof [2]instanceof [3]constructor[4]toString 前面的话 javascript有复杂的类型系统,类型识别则是基本的功能.javascrip ...

  3. Android几种打开SQLite的方法

    第一种:用SQLiteOpenHelper辅助类 SQLiteOpenHelper类可以用来创建或打开数据库,两个关键的方法:onCreate(SQLiteDatabase db)和onUpgrade ...

  4. iOS 三种收起键盘的方法

    - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typica ...

  5. 干货:结合Scikit-learn介绍几种常用的特征选择方法

    原文  http://dataunion.org/14072.html 主题 特征选择 scikit-learn 作者: Edwin Jarvis 特征选择(排序)对于数据科学家.机器学习从业者来说非 ...

  6. 【读书笔记】iOS-开发技巧-三种收起键盘的方法

    - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typica ...

  7. [原创]java WEB学习笔记79:Hibernate学习之路--- 四种对象的状态,session核心方法:save()方法,persist()方法,get() 和 load() 方法,update()方法,saveOrUpdate() 方法,merge() 方法,delete() 方法,evict(),hibernate 调用存储过程,hibernate 与 触发器协同工作

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  8. 结合Scikit-learn介绍几种常用的特征选择方法

    特征选择(排序)对于数据科学家.机器学习从业者来说非常重要.好的特征选择能够提升模型的性能,更能帮助我们理解数据的特点.底层结构,这对进一步改善模型.算法都有着重要作用. 特征选择主要有两个功能: 减 ...

  9. C#两种创建快捷方式的方法

    C#两种创建快捷方式的方法http://www.cnblogs.com/linmilove/archive/2009/06/10/1500989.html

随机推荐

  1. 【Matplotlib】线设置,坐标显示范围

    改变线的颜色和线宽 参考文章: controlling line properties Line API 线有很多属性你可以设置:线宽,线型,抗锯齿等等:具体请参考matplotlib.lines.L ...

  2. UVALive 4639 && SPOJ SPOINTS && POJ 3805 && AOJ 1298 Separate Points 求两个凸包是否相交 难度:3

    https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_probl ...

  3. AutoFac IoC DI 依赖注入

    AutoFac IoC DI 依赖注入 记录点点滴滴知识,为了更好的服务后来者! 一.为什么使用AutoFac? 之前介绍了Unity和Ninject两个IOC容器,但是发现园子里用AutoFac的貌 ...

  4. 201621123006 《Java程序设计》第8周学习总结

    1. 本周学习总结 以你喜欢的方式(思维导图或其他)归纳总结集合相关内容. 2. 书面作业 ArrayList代码分析 1.1 解释ArrayList的contains源代码 源代码如下: 由源代码可 ...

  5. iOS-----使用AddressBook添加联系人

    使用AddressBook添加联系人 添加联系人的步骤如下: 1 创建ABAddressBookRef,这就得到了对地址簿的引用. 2 调用ABPersonCreate()函数创建一个空的ABReco ...

  6. 结合File类浅析递归的使用

    递归算法就是方法自身直接或者间接地调用到了自身,它是一种写起来很简单,但理解起来不那么简单的算法. 一个功能在被重复地调用,并且运算的结果和上一次的调用有关, 这种时候,可以使用递归. * 注意: * ...

  7. 常量池之字符串常量池String.intern()

    运行时常量池是方法区(PermGen)的一部分. 需要提前了解: 1. JVM内存模型. 2. JAVA对象在JVM中内存分配 常量池的好处 常量池是为了避免频繁的创建和销毁对象而影响系统性能,其实现 ...

  8. JFreeChart的简单使用

    实例1:简单的饼图 public class Test { public static void main(String[] args) { //建立默认的饼图 DefaultPieDataset d ...

  9. windows 不能在本地计算机启动SqlServer. 参考特定服务错误代码10048

    这一般都是由于Sql Server的端口号被其他应用程序占用导致的,可以使用dos命令或者网络工具查看当前端口的使用情况,看看哪个程序占用了Sql Server的默认端口1433,将这个程序结束就可以 ...

  10. wpf 客户端【JDAgent桌面助手】开发详解(二)桌面宠物制作详解

    目录区域: wpf 客户端[JDAgent桌面助手]业余开发的终于完工了..晒晒截 wpf 客户端[JDAgent桌面助手]开发详解-开篇 wpf 客户端[JDAgent桌面助手]开发详解(一)主窗口 ...