Java进阶:JNI使用技巧点滴

yizhihongxing

Java进阶: JNI使用技巧点滴

什么是JNI

Java Native Interface(JNI)是Java平台的一个重要特性,它允许Java应用程序调用本地(C、C++)应用程序,并且本地应用程序也可以调用Java应用程序。通过JNI,Java程序员可以使用Java的优点和C的优点,实现可以同时具有可移植性和性能的应用程序。 JNI允许在Java虚拟机(JVM)中运行原生代码,并允许原生代码访问Java对象和API。

JNI的基础知识

在Java应用程序中使用JNI需要进行以下步骤:

  1. 创建native方法的声明。
  2. 编写一些本地代码。
  3. 将本地代码编译成本地库。
  4. 加载本地库。
  5. 调用本地方法。

以下是一个简单的JNI代码的例子:

public class HelloJNI {
    static {
        System.loadLibrary("hello");
    }
    public native void sayHello();
    public static void main(String[] args) {
        new HelloJNI().sayHello();
    }
}
#include <jni.h>
#include <stdio.h>
JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *env, jobject obj) {
    printf("Hello!\n");
    return;
}

上面的示例中,Java代码中创建了一个native方法,名为sayHello(),并且调用了该方法。在静态代码块中,使用System.loadLibrary函数载入本地lib库,HelloJNI,如果lib库不在默认的系统路径下,则可以使用System.load(String)指定路径进行加载。C++代码中与Java代码中的native方法名字对应的函数,库函数 JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *env, jobject obj)。在本例中,JNI函数以 Java_ 开头,后面跟上包含该函数的类名和该函数的名称。具体函数参数说明可在官方文档中查看。

JNI使用技巧

1. JNI异常处理

在JNI编程中,应该经常处理JNI异常,以提高代码可靠性和鲁棒性。可以使用三种类型的异常:Java语言异常、运行时异常和错误。

a. 抛出Java语言异常:

if (stringJava == nullptr) {
    jclass exClass = env->FindClass("java/lang/NullPointerException");
    env->ThrowNew(exClass, "String is null.");
    return NULL;
}

如果编写了一个本地方法,方法需要返回一个对象,当输入参数不符合预期或无法创建返回值时,则可以抛出Java语言异常,以通知Java代码发生了异常情况。

b. 抛出运行时异常:

jclass exClass = env->FindClass("java/lang/RuntimeException");
if (exClass != nullptr) {
    env->ThrowNew(exClass, "Null Pointer Exception.");
    return;
}

当本地方法报告错误,但不属于程序员能够捕获的一类明确异常时,应该抛出运行时异常。

c. 抛出JNI错误:

if (srcBytesLimit < destBytesLen) {
    jclass exClass = env->FindClass("java/lang/OutOfMemoryError");
    env->ThrowNew(exClass, "Out of memory.");
    return JNI_ERR;
}

JNI抛出错误通常意味着出现了Java虚拟机或JNI实现无法继续执行的灾难性情况。

2. Java对象创建和删除

在JNI中,如果需要在本地代码中创建Java对象,可以使用NewObject函数,但是需要注意的是,当本地代码完成对象工作后,应该释放对象资源。

示例代码:

jobject createobj(JNIEnv *env) {
    jclass cls = env->FindClass("java/lang/Object");
    jobject obj = env->AllocObject(cls);
    if (obj == nullptr) {
        return nullptr;
    }
    return obj;
}

void deleteobj(JNIEnv *env, jobject obj) {
    if (obj != nullptr) {
        env->DeleteLocalRef(obj);
    }
    return;
}

在上面的代码示例中,createobj()函数在本地代码中创建Java对象,如果创建成功,则返回实例对象。当完成对该对象的操作时,调用deleteobj()函数释放对象资源。

3. Java字符串和本地字符串之间的转换

在JNI编程中,经常涉及Java字符串和本地字符串之间的转换。在Java语言中,字符串是一个对象,Java字符串对象需要通过GetStringUTFChars函数访问。在将本地字符串转换为Java字符串时,可以使用NewStringUTF函数。

示例代码:

jstring from_c_to_java_string(JNIEnv *env, const char* str) {
    jstring java_string = env->NewStringUTF(str);
    return java_string;
}

char* from_java_to_c_string(JNIEnv *env, jstring j_str) {
    char* r_str = (char*)env->GetStringUTFChars(j_str, nullptr);
    return r_str;
}

void release_java_string(JNIEnv *env, jstring j_str, char* r_str) {
    env->ReleaseStringUTFChars(j_str, r_str);
    return;
}

在上面的代码示例中,from_c_to_java_string()函数可以将本地字符串转换为Java字符串。在from_java_to_c_string()函数中,Java字符串对象需要通过GetStringUTFChars()函数访问。当完成对该字符串的操作时,调用release_java_string()函数释放该字符串对象资源。

结语

本文简单介绍了JNI的基本知识和一些常用技巧,例举了JNI异常处理、Java对象创建和删除以及Java字符串和本地字符串之间的转换等。希望这篇文章能对大家学习JNI有所帮助。

参考资料

  1. 官方文档:The Java™ Native Interface: Programmer's Guide and Specification
  2. JNI官方示例:Java Native Interface (JNI) Sample Code

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java进阶:JNI使用技巧点滴 - Python技术站

(0)
上一篇 2023年5月23日
下一篇 2023年5月23日

相关文章

  • python集合类型用法分析

    Python集合类型用法分析 Python中的集合类型可用于存储一组无序且不重复的元素。本篇攻略将详细讲解Python中常用的集合类型及其用法。 集合类型 Python中常用的集合类型有三种: set frozenset dict 其中,set和frozenset是用来存储一组无序且不重复的元素的,而dict则是用来存储键值对的。 set类型 set类型使用…

    C 2023年5月22日
    00
  • OPPO R1C配置怎么样?OPPO R1C参数配置详情

    OPPO R1C配置怎么样?OPPO R1C参数配置详情 OPPO R1C是一款2015年发布的中高端智能手机。它采用了2.5D弧面玻璃设计,同时具有出色的硬件配置和摄影体验。下面将详细介绍OPPO R1C的参数配置。 CPU OPPO R1C搭载了高通骁龙615处理器,采用了八核心设计,其中四个核心采用了1.7GHz主频的Cortex-A53架构,另外四个…

    C 2023年5月23日
    00
  • 如何将JSON字符串数组转对象集合

    将JSON字符串数组转变成对象集合有以下三个步骤: 解析JSON字符串数组成JSON对象 遍历JSON对象,将每个JSON对象转化成目标对象 将转化好的目标对象添加到集合中 下面用JavaScript语言提供两种实现的示例: 示例 1 如下所示的JSON字符串数组: var jsonStrArray = [ ‘{"name":"…

    C 2023年5月23日
    00
  • 彻底掌握C语言strcat函数的用法

    下面是对彻底掌握C语言strcat函数用法的攻略: 一、strcat函数简介 strcat函数是C语言中的一个字符串拼接函数(concatenate的缩写),用于将一个字符串追加到另一个字符串的末尾。该函数的声明如下: char* strcat(char* dest, const char* src); 函数原型解释:- dest:代表目标串,即将源串的内容…

    C 2023年5月23日
    00
  • C++11各种锁的具体使用

    C++11各种锁的具体使用 在多线程编程时,锁是常用的线程同步机制之一。C++11中提供了多种不同的锁类型,用于处理不同的并发情况,本文将详细介绍这些锁的用法。 1、互斥锁(std::mutex) 使用互斥锁可以实现对共享资源的互斥访问。 #include <iostream> #include <mutex> #include &l…

    C 2023年5月22日
    00
  • C++ Boost Pool超详细讲解

    C++ Boost Pool超详细讲解 概述 C++ Boost库中的Pool库是一个有用的内存分配和管理库。它是一个头文件库,可以在C++程序中使用,使内存管理变得更加高效和简单。它的目标是在没有垃圾收集器的情况下提高内存分配的效率。 Pool库提供了两个主要的类来支持内存池: boost::pool: 这个类定义了一个通用内存池,可以用于管理任意大小的对…

    C 2023年5月23日
    00
  • VScode中添加头文件和源文件(C/C++)的方法

    添加头文件和源文件是开发C/C++程序的必备步骤,本文将详细讲解在VScode中添加头文件和源文件的方法,以便程式师开发更加便捷。 添加头文件 要在VScode中添加头文件,需要按照以下步骤进行操作: 1.为了创建一个C/C++项目,您需要在终端中使用以下命令来创建一个名称为myproject的新目录: mkdir myproject cd myprojec…

    C 2023年5月23日
    00
  • 详解C/C++如何获取路径下所有文件及其子目录的文件名

    获取一个文件夹下的所有文件及其子目录的文件名可以通过递归遍历文件夹来完成。以下是几个示例代码,演示如何实现这个功能。 方法一:使用C++17中的std::filesystem 基于C++17标准,可以使用std::filesystem库来遍历目录。下面是示例代码: #include <iostream> #include <filesyst…

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部