Java中JNI的使用(下)

数组的操作

数组是一个很常用的数据类型,在但是在 JNI 中并不能直接操作 jni 数组(比如 jshortArray、jfloatArray)。使用方法是:

  1. 获取数组长度:jsize GetArrayLength(jarray array)
  2. 创建新数组: ArrayType New<PrimitiveType>Array(jsize length);
  3. 通过JNI数组获取一个C/C++数组:<type>* Get<type>ArrayElements(jshortArray array, jboolean *isCopy)
  4. 指定原数组的范围获取一个C/C++数组(该方法只针对于原始数据数组,不包括Object数组):void Get<PrimitiveType>ArrayRegion(JNIEnv *env, ArrayType array, jsize start, jsize len, NativeType *buf);
  5. 设置数组元素:void Set<type>ArrayRegion(jshortArray array, jsize start, jsize len,const <type> *buf)。again,如果是Object数组需要使用:void SetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index, jobject value);
  6. 使用完之后,释放数组:void Release<type>ArrayElements(jshortArray array, jshort *elems, jint mode)

有点要说明的:

1、上面的3中的 isCopy:当你调用 getArrayElements 时 JVM(Runtime)可以直接返回数组的原始指针,或者是 copy 一份,返回给你,这是由 JVM 决定的。所以 isCopy 就是用来记录这个的。他的值是 JNI_TURE 或者 JNI_FALSE

2、6释放数组。一定要释放你所获得数组。其中有一个mode参数,其有三个可选值,分别表示:

  • 0

    • 原始数组:允许原数组被垃圾回收。
    • copy: 数据会从get返回的buffer copy回去,同时buffer也会被释放。
  • JNI_COMMIT
    • 原始数组:什么也不做
    • copy: 数据会从get返回的buffer copy回去,同时buffer不会被释放。
  • JNI_ABORT
    • 原始数组:允许原数组被垃圾回收。之前由JNI_COMMIT提交的对数组的修改将得以保留。
    • copy: buffer会被释放,同时buffer中的修改将不会copy回数组!

关于引用与垃圾回收

比如上面有个方法传了一个 jobject 进来,然后我把她保存下来,方便以后使用。这样做是不行哒!因为他是一个 LocalReference,所以不能保证 jobject 指向的真正的实例不被回收。也就是说有可能你用的时候那个指针已经是个野指针的。然后你的程序就直接 Segment Fault 了,呵呵。

在JNI中提供了三种类型的引用:

  1. Local Reference:即本地引用。在JNI层的函数,所有非全局引用对象都是Local Reference, 它包括函数调用是传入的jobject和JNI成函数创建的jobject。Local Reference的特点是一旦JNI层的函数返回,这些jobject就可能被垃圾回收。
  2. Glocal Reference:全局引用,这些对象不会主动释放,永远不会被垃圾回收。
  3. Weak Glocal Reference:弱全局引用,一种特殊的Global Reference,在运行过程中有可能被垃圾回收。所以使用之前需要使用jboolean IsSameObject(jobject obj1, jobject obj2)判断它是否已被回收。

Glocal Reference:
1. 创建:jobject NewGlobalRef(jobject lobj);
2. 释放:void DeleteGlobalRef(jobject gref);

Local Reference:
LocalReference也有一个释放的函数:void DeleteLocalRef(jobject obj),他会立即释放Local Reference。 这个方法可能略显多余,其实也是有它的用处的。刚才说Local Reference会再函数返回后释放掉,但是假如函数返回前就有很多引用占了很多内存,最好函数内就尽早释放不必要的内存。

关于JNI_OnLoad

开头提到 JNI_OnLoad 是 Java1.2 中新增加的方法,对应的还有一个 JNI_OnUnload,分别是动态库被 JVM 加载、卸载的时候调用的函数。有点类似于 Windows 里的 DllMain。
前面提到的实现对应 native 的方法是实现 javah 生成的头文件中定义的方法,这样有几个弊端:

  1. 函数名太长。很长,相当长。
  2. 函数会被导出,也就谁说可以在动态库的导出函数表里面找到这些函数。这将有利于别人对动态库的逆向工程,因此带来安全问题。

现在有了JNI_OnLoad,情况好多了。你不光能在其中完成动态注册 native 函数的工作还可以完成一些初始化工作。Java 对应的有了 jint RegisterNatives(jclass clazz, const JNINativeMethod *methods,jint nMethods)函数。参数分别是:

  • jclass clazz,于native层对应的java class
  • const JNINativeMethod *methods这是一个数组,数组的元素是JNI定义的一个结构体JNINativeMethod
  • 上面的数组的长度

JNINativeMethod:代码中的定义如下


1

2

3

4

5

6

7

8

9

10

/*

 * used in RegisterNatives to describe native method name, signature,

 * and function pointer.

 */

typedef struct {

    char *name;

    char *signature;

    void *fnPtr;

} JNINativeMethod;

所以他有三个字段,分别是

于是现在你可以不用导出 native 函数了,而且可以随意给函数命名,唯一要保证的是参数及返回值的统一。然后需要一个 const JNINativeMethod *methods 数组来完成映射工作。

原文地址:https://www.cnblogs.com/ssming/p/9759823.html

时间: 2024-10-10 05:24:34

Java中JNI的使用(下)的相关文章

Java中JNI的使用详解第一篇:HelloWorld

今天开始研究JNI技术,首先还是老套路,输出一个HelloWorld:具体流程如下:在Java中定义一个方法,在C++中实现这个方法,在方法内部输出"Hello World",然后再回到Java中进行调用.分为以下步骤: 第一步:在Eclipse中建立一个类:JNIDemo 1 package com.jni.demo; 2 public class JNIDemo { 3 //定义一个本地方法 4 public native void sayHello(); 5 public sta

Java中JNI的使用详解第二篇:JNIEnv类型和jobject类型的解释

上一篇说的是一个简单的应用,说明JNI是怎么工作的,这一篇主要来说一下,那个本地方法sayHello的参数的说明,以及其中方法的使用 首先来看一下C++中的sayHello方法的实现: [cpp] view plaincopy JNIEXPORT void JNICALL Java_com_jni_demo_JNIDemo_sayHello (JNIEnv * env, jobject obj) { cout<<"Hello World"<<endl; } 对于

java中获得src路径下文件的常用方法

在代码中一般读取src下的配置文件 读取src路径下的log4j.properties和message.properties 读取message.properties文件并将properties中的键值对转为map PropertiesServlet.class.getClassLoader().getResourceAsStream("/message.properties");返回值是一个InputStream   /**      * 根据java标准properties文件读取

Java中JNI的使用详解第三篇:JNIEnv类型中方法的使用

转自: http://blog.csdn.net/jiangwei0910410003/article/details/17466369 上一篇说道JNIEnv中的方法的用法,这一篇我们就来通过例子来看一下这些方法的使用: 首先是第一个例子:在Java代码中定义一个属性,然后再C++代码中将其设置成另外的值,并且输出来 先来看一下Java代码: [java] view plain copy package com.jni.demo; public class JNIDemo { public i

Java中查询某个日期下所有时间段的数据

除了利用时间段进行查询外,还有一个方法: 利用mybatis中的函数,将datetime转为date <if test="purch_date!= null and purch_date!=''"> date(purch_date) = #{purch_date} </if> 原文地址:https://www.cnblogs.com/sanhao/p/9504015.html

java中默认lang包下的Math.round和Math.rint的区别

public static double rint ( double ): 取最接近的整数(若相同则取偶数),然后转为 double 类型 public static int round ( float ): 取最接近的整数(若相同则取大数),然后转为 int 类型 public static long round ( double ): 取最接近的整数(若相同则取大数),然后转为 long 类型 public static double ceil ( double ) : 返回 ≥ 参数的最小

java中变量使用的总结

java中整数默认为int,小数默认为double. float n5=1.3; 这个句子就会报错,应该修改成这样float n5=1.3f; 八大基本类型 变量类型 位数 范围 备注 Byte 8位 -27-------27-1 带符号整数 Short 16位 -215-------215-1 带符号整数 Int 32位 -231-------231-1 带符号整数 Long 64位 -263------263-1 带符号整数 Char 16位 0-----216-1 无符号整数 Float

1.JAVA中使用JNI调用C++代码学习笔记

Java 之JNI编程1.什么是JNI? JNI:(Java Natibe Inetrface)缩写. 2.为什么要学习JNI?  Java 是跨平台的语言,但是在有些时候仍然是有需要调用本地代码 (这些代码通常是由C/C++编写的). Sun公司提供的JNI是Java平台的一个功能强大的接口.这个JNI接口提供了Java与操作系统本地代码互相调用的功能.(即java调用C++代码) 最简单的Java调用C/C++代码步骤 1.创建TestNativeCode工程,新建cn.itcast包,新建

解析Java的JNI编程中的对象引用与内存泄漏问题

JNI,Java Native Interface,是 native code 的编程接口.JNI 使 Java 代码程序可以与 native code 交互--在 Java 程序中调用 native code:在 native code 中嵌入 Java 虚拟机调用 Java 的代码.JNI 编程在软件开发中运用广泛,其优势可以归结为以下几点: 利用 native code 的平台相关性,在平台相关的编程中彰显优势. 对 native code 的代码重用.native code 底层操作,更