有关JAVA虚拟机本地异常机制的思考
有关JAVA虚拟机本地异常机制的思考By 姜江jznsmail@tom.com>http://blog.csdn.net/jznsmail在JAVA语言中,如果需要自己实现一个异常函数可以通过在函数后通过throws来指定抛出何种类型的异常,如果是类则可以通过继承Exception类来抛出指定类型的异常。下面以自定义异常函数为列子:public class ExceptionTest{ pub
有关JAVA虚拟机本地异常机制的思考
By 姜江<jznsmail@tom.com>
http://blog.csdn.net/jznsmail
在JAVA语言中,如果需要自己实现一个异常函数可以通过在函数后通过throws来指定抛出何种类型的异常,如果是类则可以通过继承Exception类来抛出指定类型的异常。下面以自定义异常函数为列子:
public class ExceptionTest
{
public void Exception1() throws Exception
{
throw new Exception();
}
public static void main(String args[])
{
ExceptionTest exp = new ExceptionTest();
exp.Exception1(); /* Error */
}
}
上面代码是一个抛出异常的函数,在main函数中会调用到该异常函数。不过上面的代码有点问题,在JAVA语言中如果定义了一个异常函数,则调用者应该负责捕获该函数返回的异常,因此需要在exp.Exception1()位置加入try{}catch语句。
try
{
exp.Exception1();
}
catch(Exception e)
{
System.out.println("Catch Exception1 Exception...");
}
这是属于JAVA语言中异常处理的标准情况,那么对于本地代码的异常处理机制会是怎样的?
编写如下代码:
public class ExceptionTest
{
static
{
System.loadLibrary("ExceptionTest");
}
public native void Except1() throws Exception;
public native void Except2();
public void Except3()
{
System.out.println("################Java Except3################");
}
public static void main(String args[])
{
ExceptionTest exp = new ExceptionTest();
try
{
exp.Except1();
}
catch(Exception e)
{
System.out.println("############Catch Exception 1################");
}
exp.Except2();
exp.Except3();
System.out.println("Successfull Exit...");
}
}
这段代码定义了两个函数Exception1(),Exception2(),不过只有Exception1()函数声明了会抛出一个Exception异常,而Exception2()函数并没有直接声明,但是我会使得Exception2()函数也抛出一个Exception异常,看看最后的结果是怎样的。
通过JNI接口我可以定义一个动态连接库文件ExceptionTest.DLL(Linux下是.so文件):
#include <stdio.h>
#include <jni.h>
#include "ExceptionTest.h"
JNIEXPORT void JNICALL Java_ExceptionTest_Except1
(JNIEnv *env, jclass)
{
//jthrowable exp;
env->ThrowNew(env->FindClass("java/lang/Exception"), "####Except1:This is C Code.####/n");
printf("###############Native Fun Except1#################/n");
}
JNIEXPORT void JNICALL Java_ExceptionTest_Except2
(JNIEnv *env, jclass)
{
env->ThrowNew(env->FindClass("java/lang/Exception"), "####Except2:This is C Code.####/n");
printf("###############Native Fun Except2#################/n");
}
在函数定义中Exception2实际上也抛出了一个Exception的异常,JAVA代码调用本地代码的运行结果是:
###############Native Fun Except1#################
############Catch Exception 1################
###############Native Fun Except2#################
Exception in thread "main" java.lang.Exception: ####Except2:This is C Code.####
at ExceptionTest.Except2(Native Method)
at ExceptionTest.main(ExceptionTest.java:34)
结果显示Except2()函数抛出了一个异常,但是我们并没有捕获,因此程序异常退出了。
如果我们在JAVA代码中对Exception2()进行捕获结果会怎样?在Exception2()函数位置使用try{}catch语句后运行结果是:
###############Native Fun Except1#################
############Catch Exception 1################
###############Native Fun Except2#################
############Catch Exception 2################
################Java Except3################
Successfull Exit...
这个列子证明Exception2()函数抛出的异常在我们的JAVA代码中被捕获了。
因此,在JAVA VM设计中,KNI层的代码会抛出一系列的异常,但是有些JAVA库函数中声明了native函数将会throws某种类型的异常,而有些却没有明确声明,起始这个对于KVM的实现者来说并不重要,实现者只需要保证与机器相关代码的正确性,并且返回JAVA规范所规定的异常即可。至于如何和何时捕获异常那是调用者的事情,即使用库函数者的事情了。
伪代码:
public class Graphics
{
...
public native void DrawChar(int x, int y, char c);
...
}
以上函数并没有显示的声明该函数会返回一个异常。
KNI层的伪代码实现如下:
Java_javax_microedition_lcdui_Graphics_drawChar()
{
...
if(!checkAnchor(anchor, VCENTER))
{
KNI_ThrowNew(midpIllegalArgumentException, NULL);
}
else
{
...
}
...
}
通过上面的KVM实现的伪代码可以看出,JAVA库函数中DrawChar并没有指定该函数会抛出任何异常信息,但是在实际的本地代码的实现中却抛出了IllegalArgumentException异常。因此在KVM的实现过程中并不能仅仅通过KNI接口函数定义中是否明确指示函数抛出某种类型的异常,来判断底层移植接口是否应该抛出异常信息。具体的异常抛出应该参考J2ME的实现规范。
由此可知,盲目的相信已有代码的正确性并不是一件好事,正如今天老大说的,应该抱着怀疑的态度来看待任何“小”问题:)
更多推荐
所有评论(0)