Jimmy Chen

A Programmer

(原创) JNI编程指南与规范 第六章 刻意练习

第六章之刻意练习

  经过第六章的学习,基本了解JNI的异常处理了,现在我们来刻意练习一下

practice 1, 在native层获取Java异常并将异常抛出给Java层

我们需要在native方法中实现除法,除法的除数是不能为零的,所以如果Java在调用native方法的除法时,穿进去的第二个参数为0的话,我们就要抛出一个 java.lang.ArithmeticExpection:/by zero的异常到Java空间中,然后再Java空间中处理这个异常。Java侧的工作就比较简单了,我们只要在Java侧获取除法需要的两个double值,然后调用native层的方法就可以了。OK,下面我们开始编程吧,有时间还是建议先自己写一下代码。

下面是我写的代码

Java侧代码

import java.util.Scanner;
import java.lang.ArithmeticException;

class Divition {
    
    private native double div(double a, double b) throws ArithmeticException;
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        Divition di = new Divition();
        System.out.print("Enter the first double number: ");
        double a = sc.nextDouble();
        System.out.print("Enter the second double number: ");
        double b = sc.nextDouble();
        double result = 0.0;
        
        try {
            result = di.div(a, b);
            System.out.println(a + " / " + b + " = " + result);
        } catch(ArithmeticException e) {
            e.printStackTrace();
        }
    }   
    
    static {
        System.loadLibrary("Divition");
    }
}

代码意图明显,就是获取输入,然后再try catch中调用方法。下面看看native层代码怎么实现

#include <jni.h>
#include <stdio.h>

JNIEXPORT jdouble JNICALL native_div(JNIEnv * env, jobject obj, jdouble a, jdouble b)
{
    if(b == 0)   {
        jclass clazz = (*env)->FindClass(env, "java/lang/ArithmeticException");
        if(clazz != NULL) {
            (*env)->ThrowNew(env, clazz, "/ by zero");
        }
        (*env)->DeleteLocalRef(env, clazz);
        return NULL;
    }
    
    return (a / b);
}

static const JNINativeMethod gMethods[] = {
    {"div", "(DD)D", native_div}
};

static jclass myClass;
static const char * ClassName = "Divition";
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM * vm, void * reversed)
{
    JNIEnv * env = NULL;
    
    if((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_6) != JNI_OK) {
        printf("GetEnv return error.\n");
        return -1;
    }
    
    myClass = (*env)->FindClass(env, ClassName);
    if(myClass == NULL) {
        printf("FindClass return error.\n");
        return -1;
    }
    
    if((*env)->RegisterNatives(env, myClass, gMethods, sizeof(gMethods)/sizeof(gMethods[0])) < 0) {
        printf("RegisterNatives return error\n");
        return -1;
    }
    
    return JNI_VERSION_1_6;
}

上面的处理也是比较简单的,在函数开始的时候就直接判断除数是否为0,如果为零就找到对应的异常类,然后调用ThrowNew,将异常抛出到Java处。

  接下来直接编译运行就好了。这里主要联系下怎么获取Java中的异常类,然后将其抛出到Java层。

practice 2,在native中调用Java的方法,并在native层中处理异常

这里做同样的练习好了,现在我们在Java层中编写除法的代码,然后我们在native层获取输入,然后调用Java层的除法,然后判断是否有异常抛出,如果与的话就处理异常,否则打印结果。

下面是我写的代码

Java侧代码:

import java.lang.ArithmeticException;

class Divition2 {
    private native void callDiv();
    
    private double div(double a, double b) throws ArithmeticException {
        if(b == 0) {
            throw new ArithmeticException("/ by zero");
        } else {
            return (a / b);
        }
    }
    
    public static void main(String[] args) {
        Divition2 di = new Divition2();
        di.callDiv();
    }
    
    static {
        System.loadLibrary("Divition2");
    }
}

这里不多解释了,代码简单,看一下就懂

ntive侧代码:

#include <jni.h>
#include <stdio.h>

JNIEXPORT void JNICALL native_callDiv(JNIEnv * env, jobject obj)
{
    jdouble a = 0.0;
    jdouble b = 0.0;
    jdouble result = 0.0;
    jthrowable exc;
    jclass clazz;
    jmethodID mid;
    
    printf("Enter the first double number: ");
    scanf("%lf", &a);
    printf("Enter the second double number: ");
    scanf("%lf", &b);
    
    clazz = (*env)->GetObjectClass(env, obj);
    mid = (*env)->GetMethodID(env, clazz, "div", "(DD)D");
    if(mid == NULL) {
        printf("GetMethodID return error\n");
        return;
    }
    
    result = (*env)->CallDoubleMethod(env, obj, mid, a, b);
    exc = (*env)->ExceptionOccurred(env);
    if(exc) { // 有异常出现
        (*env)->ExceptionDescribe(env);
        (*env)->ExceptionClear(env);
    }
    else
    {
        printf("%lf / %lf = %lf\n", a, b, result);
    }
    
    return;
}

static const JNINativeMethod gMethods[] = {
    {"callDiv", "()V", native_callDiv}
};


static jclass myClass;
static const char * ClassName = "Divition2";
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM * vm, void * reversed)
{
    JNIEnv * env = NULL;
    
    if((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_6) != JNI_OK) {
        printf("GetEnv return error.\n");
        return -1;
    }
    
    myClass = (*env)->FindClass(env, ClassName);
    if(myClass == NULL) {
        printf("FindClass return error.\n");
        return -1;
    }
    
    if((*env)->RegisterNatives(env, myClass, gMethods, sizeof(gMethods)/sizeof(gMethods[0])) < 0) {
        printf("RegisterNatives return error\n");
        return -1;
    }
    
    return JNI_VERSION_1_6;
}

** 此文为博主原创文章,转载请注明出处 **

发表评论

电子邮件地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d 博主赞过: