第17章 异常

javac为remainder ()方法产生下列字节码序列:

// The main bytecode sequence for remainder ();
// Push local variable 0 {arg passed as
0 iload_0 // dividend)
// Push the minimum integer value
1 ldc #1 <Integer -2147483648>

// If the dividend isn't equal to the minimum
// integer, jump to the remainder calculation
3 if_icmpne 19

// Push local variable 1 (arg pased as

6 iload_l // divisor)

// Push -1

7 iconst_ml

// If the divisor isn't equal to -1, jump
// to the remainder calculation

8 if_icmpne 19

// This is an overflow case, bo throw an
// exception. Create a new OverflowException,
// push reference to it onto the stack

11 new #4 <ClaBS OverflowException>
14 dup //make a copy of the reference

//Pop one copy of the reference and invoke
// the <init> method of new OverflowException
// object

15 invokeapecial #10 <Method OverflowException()>

// Pop the other reference to the
// OverflowException and throw it

18 athrow

// Calculate the remainder
// Puab local variable 0 (arg passed as
19 iload_0 // dividend)
// Push local variable 1 (arg passed as
20 iload_l // divisor)
// Pop divisor; pop dividend; calculate,push
21 irem // remainder
22 ireturn // Return int on top of stack (the remainder)

// The bytecode sequence for the
// catch (ArithmeticBxception) clause:

// Pop the reference to the
// ArithmoticException because it isn't used

23 pop //by this catch clause.

24 new #2 <Class DivideByZeroException>
// Create and push reference to new object of
// class DivideByZeroException.
// Duplicate the reference to the new object
// on the top of the stack because it must be
// both initialized and thrown. The
// initialization will consume the copy of the

27 dup // reference created by the dup,

// Call the no-arg <init> method for the
// DivideByZeroException to initialize it.

// This instruction will pop the top reference
// to the object.

28 invokespecial #9 <Method DivideByZeroException()>

// Fop the reference to a Throwable object, in
// this case the DivideByZeroException,

31 athrow // and throw the exception.
方法remainder ()的字节码序列包含两个部分:第一部分是方法的正常执行路径,该部分指的是pc指针偏移量0到22;第二部分是catch子句,该部分指的是pc指针偏移量23到31。

// Overflow can occur in division when dividing
// the negative integer of the largest possible
// magnitude (Integer.MIN_VALUE) by -1, because
// this would Juat flip the sign, but there is no
// way to represent that nunber in an int.
if((dividend Integer.MIN_VALUE> &&(divisor==-1)){
throw new OverflowException();
}
所有作为Error和RuntimeException的子类的异常都是未检验的。

17.2异常表
主字节码序列中的指令irem可能会抛出ArithmeticException异常。如果发生这种情况,Java 虚拟机将在表中査找异常,然后跳转到实现catch子句的字节码序列。每个捕获异常的方法都与异常表相关联,该异常表与方法的字节码序列一起送到Class文件中。每一个被try语句块捕获的异常都与异常表中的一个入口(项)相对应。异常表中的每个入口都包括四部分信息:

•起点。

•终点。

•将要跳转到的字节码序列中的pc指针偏移量。

•被捕获的异常类的常量池索引。

下面是NitPickyMath类的remainder ()方法的异常表:

Exception table:

from to target type

I9 23 23 <Class java.lang.ArithmeticException>

上述异常表说明,ArithmeticException异常在pc指针偏移量19到22 (含)中被捕获。try语句块的终点值在“to”栏中列出。这个终点值总是比捕获异常位置的pc指针偏移量的最大值还要大1。在这个例子中,终点值为23,但捕获异常位置的pc偏移量最大值为22。偏移量19到22 (含)之间的语句对应于实现remainder ()内try语句块代码的字节码序列。上述表格中列出的target栏指出了如果ArithmeticException异常在pc指针偏移量19到22 (含)之间抛出,pc指针偏移量将要跳转到的位置。

如果异常在方法执行时抛出,Java虚拟机将会在整个异常表中搜寻相匹配的项。如果当前程序计数器在异常表入口所指定的范围内,而且所抛出的异常类是该入口所指向的类(或为指定类的子类),那么该入口即为所搜寻的入口。Java虚拟机按照每个入口在表中出现的顺序进行检索。当遇到第一个匹配项时,虚拟机将程序计数器设为新的pc指针偏移量位置,然后从该位置 继续执行。如果没有发现相匹配的项,虚拟机将当前栈帧从栈中弹出,再次抛出同样的异常。 当Java虚拟机弹出当前栈帧时,虚拟机马上终止当前方法的执行,并且返回至调用本方法的方法 中,但是并非继续正常执行该方法,而是在该方法中拋出同样的异常,这就使得虚拟机在该方 法中再次执行同样的搜寻异常表的操作。

Java程序员可以使用throw语句抛出异常,正如remainder ()方法中的catch ( Arithmetic Exception)子句,这里创建了异常DivideByZcjroExceplion,并将其抛出。执行抛出异常操作的 字节码如表17-1所示。

指令athrow从栈顶端弹出宇,并假设它是一个对象的引用,该对象为Throwable类的子类的实例(或者就是Throwable类的实例)。所抛出异常的类型由弹出的对象引用类型决定。

猜你喜欢

转载自www.cnblogs.com/mongotea/p/11980084.html