本文是《The Java Native Interface Programmer’s Guide and Specification》读书笔记


前面我们学习了如何在JNI中通过参数来使用Java中的普通变量,下面我们来学习如何在JNI中使用Java类的普通方法与成员变量;Java中类有两个区域:每个类的实例的私有区域和所有实例共享的类的静态区域,JNI也提供了相应的方法来操作这两个区域中的方法与变量。首先以一个简单例子来说明如何在JNI中操作类实例的私有区域:

1 变量的操作

1.1 类实例的私有区域(成员变量)操作:

Java类的代码为:

class InstanceFieldAccess {
private String s;//类实例的私有区域,修饰符也可以为public
//JNI方法,用来修改类实例的私有区域的变量
private native void accessField();
public static void main(String args[]) {
InstanceFieldAccess c = new InstanceFieldAccess();
c.s = "abc";
c.accessField();
System.out.println("In Java:");
System.out.println(" c.s = \"" + c.s + "\"");
}
static {
System.loadLibrary("InstanceFieldAccess");
}
}

JNI方法的实现为:

JNIEXPORT void JNICALL
Java_InstanceFieldAccess_accessField(JNIEnv *env, jobject obj)
{
jfieldID fid; /* 保存区域的标识符 */
jstring jstr;
const char *str;
/* 得到obj对象的类的引用,这里是前面的类InstanceFieldAccess的引用 */
jclass cls = (*env)->GetObjectClass(env, obj);
printf("In C:\n");
/* 在类的私有区域里寻找名为s的区域标识 */
fid = (*env)->GetFieldID(env, cls, "s",
"Ljava/lang/String;");
if (fid == NULL) {
return; /* failed to find the field */
}
/* 取得相应区域标识的实例*/
jstr = (*env)->GetObjectField(env, obj, fid);
str = (*env)->GetStringUTFChars(env, jstr, NULL);
if (str == NULL) {
return; /* out of memory */
}
printf(" c.s = \"%s\"\n", str);
(*env)->ReleaseStringUTFChars(env, jstr, str);
/* 创建一个新的String对象 */
jstr = (*env)->NewStringUTF(env, "123");
if (jstr == NULL) {
return; /* out of memory */
}
/*将创建的String对象的值写入到相应区域标识里*/
(*env)->SetObjectField(env, obj, fid, jstr);
}

执行完这个JNI方法后,s的值就被修改为"123"了;

1.2 对类的静态区域的(类变量)操作

Java类的定义为:

public StaticFieldAccess{
private static int si;
private native void accessField();
...
}

对应的JNI的方法的实现为:

JNIEXPORT void JNICALL
Java_StaticFieldAccess_accessField(JNIEnv *env, jobject obj)
{
jfieldID fid; /*用来保存区域的标识 */
jint si;
/* Get a reference to obj’s class */
jclass cls = (*env)->GetObjectClass(env, obj);
printf("In C:\n");
/* Look for the static field si in cls */
fid = (*env)->GetStaticFieldID(env, cls, "si", "I");
if (fid == NULL) {
return; /* field not found */
}
/* Access the static field si */
si = (*env)->GetStaticIntField(env, cls, fid);
printf(" StaticFieldAccess.si = %d\n", si);
(*env)->SetStaticIntField(env, cls, fid, 200);
}

由上可以看出,在JNI中操作类实例的私有区域与操作类的静态区域是类似的,在得到区域的标识时,使用不同的方法就可以了。前面的操作看起来比较复杂,是因为String不是基本的类型,需要一些特殊的处理,而int为基本类型,不需要进行特殊的处理;

2. 普通方法的使用

2.1 类的实例的成员方法的使用

Java中类的定义如下:

public class  InstanceMethodCall{
private native void nativeMethod();
private void callback(){
System.out.println("In Java");
}
...
}

JNI方法的实现

JNIEXPORT void JNICALL
Java_InstanceMethodCall_nativeMethod(JNIEnv *env, jobject obj)
{
jclass cls = (*env)->GetObjectClass(env, obj);
//得到对应方法的标识ID
jmethodID mid =
(*env)->GetMethodID(env, cls, "callback", "()V");
if (mid == NULL) {
return; /* method not found */
}
printf("In C\n");
//调用对应的成员方法,相应的还有CallIntMethod方法调用返回值为int的方法,CallObjectMethod方法调用返回值为对象的方法(数组,String等)等;
(*env)->CallVoidMethod(env, obj, mid);
}

JNI方法调用类的普通方法的流程参考以上代码;

2.2类方法的使用

java类的定义如下:

public class StaticMethodCall{
private native void nativeMethod();
private static void callback(){
System.out.println("In java");
}
...
}

对应的JNI方法的实现为:

JNIEXPORT void JNICALL
Java_StaticMethodCall_nativeMethod(JNIEnv *env, jobject obj)
{
jclass cls = (*env)->GetObjectClass(env, obj);
jmethodID mid =
(*env)->GetStaticMethodID(env, cls, "callback", "()V");
if (mid == NULL) {
return; /* method not found */
}
printf("In C\n");
(*env)->CallStaticVoidMethod(env, cls , mid);
}

类方法与类的实例的成员方法的调用也类似,只不过在获得方法标识时,需要调用不同的方法;

2.3 构造方法的调用

构造方法的调用与实例的成员方法的调用类似,下面以字符串的构造函数String(char[]chars)的调用为例:

 jstring
MyNewString(JNIEnv *env, jchar *chars, jint len)
{
jclass stringClass;
jmethodID cid;
jcharArray elemArr;
jstring result;
stringClass = (*env)->FindClass(env, "java/lang/String");
if (stringClass == NULL) {
return NULL; /* exception thrown */
}
/* 得到构造函数String(char[]) 的方法标识 */
cid = (*env)->GetMethodID(env, stringClass,
"<init>", "([C)V");
if (cid == NULL) {
return NULL; /* exception thrown */
}
/* 创建一个charArray来保存这些字符 */
elemArr = (*env)->NewCharArray(env, len);
if (elemArr == NULL) {
return NULL; /* exception thrown */
}
(*env)->SetCharArrayRegion(env, elemArr, 0, len, chars);
/* 构造一个 java.lang.String的对象,这就是调用构造函数的地方 */
result = (*env)->NewObject(env, stringClass, cid, elemArr);
/* 释放掉本地的引用 */
(*env)->DeleteLocalRef(env, elemArr);
(*env)->DeleteLocalRef(env, stringClass);
return result;
}

Java Native Interfce三在JNI中使用Java类的普通方法与变量的更多相关文章

  1. Java基础---IO(三)--IO包中的其他类

    第一讲     对象序列化 一.概述 将堆内存中的对象存入硬盘,保留对象中的数据,称之为对象的持久化(或序列化).使用到的两个类:ObjectInputStream和ObjectOutputStrea ...

  2. Java Native Interface 二 JNI中对Java基本类型和引用类型的处理

    本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 Java编程里会使用到两种类型:基本类型(如 ...

  3. Android jni中回调java的方法

    在上一篇的基础上,添加在C++代码中回调java方法. 代码如下: Demo.java 中添加callback函数, 打印一条log. package com.example.scarecrow.dy ...

  4. jni中调用java方法获取当前apk的签名文件md5值

    相应的java方法: void getsign(Context context) throws Exception { PackageInfo localPackageInfo = context.g ...

  5. Java高精度学习第三弹——ACM中使用JAVA的详细介绍

    Chapter I. Java的优缺点各种书上都有,这里只说说用Java做ACM-ICPC的特点: (1) 最明显的好处是,学会Java,可以参加Java Challenge . (2) 对于熟悉C/ ...

  6. [原创]Java中使用File类的list方法获取一定数量的文件:FilenameFilter接口的特殊用法

    前言:有时候我们可能会遇到这样一个问题:需要遍历一个包含极多文件的文件夹,首先想到的肯定是使用File.list()方法,该方法返回一个String[],但是如果文件达到几亿呢?这个时候我们就需要分批 ...

  7. 编写Java程序,创建Dota游戏中的兵营类,兵营类有一个类成员变量count、一个实例变量name和另一个实例变量selfCount。

    返回本章节 返回作业目录 需求说明: 创建Dota游戏中的兵营类 兵营类有一个类成员变量count.一个实例变量name和另一个实例变量selfCount. count表示的是兵营已经创建士兵的总数: ...

  8. Java中的Object类的toString()方法,equals()方法

    Object类是所有类的父类,若没有明确使用extends关键字明确表示该类继承哪个类,那么它就默认继承Object类,也就可以使用Object中的方法: 1.toString 如果输出一个对象的时候 ...

  9. 编写Java程序,在子类老虎中重写父类动物的吃食方法

    返回本章节 返回作业目录 需求说明: 在子类老虎中重写父类动物的吃食方法 实现思路: 在子类老虎中重写父类动物的吃食方法的实现思路如下: 创建各种动物的父类Animal类,在该类中定义eat()方法. ...

随机推荐

  1. Jsp 错题分析

    ArrayList删除元素通过RemoveAt(int index)来删除指定索引值的元素 运行时异常都是RuntimeException类及其子类异常,如NullPointerException.I ...

  2. C++的vector对象

    C++的vector使用 标签(空格分隔): C++ 标准库类型vector表示对象的集合,其中所有对象的类型都相同.集合中的每个对象都有一个与之对应的索引,索引用于访问对象,因为vector容纳着其 ...

  3. BZOJ1925[SDOI2010]地精部落

    Description 传说很久以前,大地上居住着一种神秘的生物:地精. 地精喜欢住在连绵不绝的山脉中.具体地说,一座长度为 N 的山脉 H可分 为从左到右的 N 段,每段有一个独一无二的高度 Hi, ...

  4. pcl曲面重建模块-贪婪三角形投影算法实例

    贪婪三角形投影算法 在pcl-1.8测试 #include <pcl/point_types.h> #include <pcl/io/pcd_io.h> #include &l ...

  5. redis 学习笔记(1)-编译、启动、停止

    一.下载.编译 redis是以源码方式发行的,先下载源码,然后在linux下编译 1.1 http://www.redis.io/download 先到这里下载Stable稳定版,目前最新版本是2.8 ...

  6. 【转】一些 SQLite技巧

    部分来源于网络 SQLite 删除重复行 需求:现存在一张表tender_to_detailedlist,然后里面的列tender_id和detailedlist_id具有相同的数据且不确定相同数据的 ...

  7. 如何修改Total Commander配件文件的位置

    今天测试了一下Total Commander最新版的安装文件,测试完成后,并删除.结果导致原先一直在使用的绿色版的Total Comander配件文件变成了测试的配件文件,导致许多配置都丢失了,因此不 ...

  8. php 字符串和数字比较一些问题

    本文章来给大家介绍关于php 字符串和数字比较一些问题,因为数字与字符在php中是不同的数据类型,所以在比较时可能会有很多的问题. ,1,2等等,其中0标示成功,其他表示不同的错误代码.程序通过 if ...

  9. XStream简单入门

    简单的讲,XStream 涉及的就五个知识点:详情参考 官网 混叠,注解,转换器,对象流和操作json! 下面就用几个简单的例子来实现上述五个知识点! 基本步骤: 第1步:创建XStream对象. 通 ...

  10. CentOS 6.5安装在VMWare中Bridge模式下网卡eth0不能自动激活的问题

    VMWare 12.5.2 CentOS 6.5 basic VMWare网卡配置选择Bridge方式 问题: 默认情况下ifconfig命令只能看到网络设备lo,看不到eth0,也没有分配合理的IP ...