java中finally子句的分析

来源:互联网 发布:最奇葩的淘宝差评有图 编辑:程序博客网 时间:2024/06/11 19:24

java中finally子句是怎么运行的?

看下面的程序:

public class JVMTest {
    
    public static void main(String[] args){
        System.out.println("aa:" + aa());
    }
    public static int aa(){
        int a = 1;
        int b = 10;
        try{
            System.out.println("abc");
            return a;
        }finally{
            a = 2;
            System.out.println("a: "+ a);          
        }
    }  
}

运行结果为:

abc
a: 2
aa:1

由此可知:在try语句中,在执行return语句时,要返回的结果已经准备好了,就在此时,程序转到finally执行了。

在转去之前,try中先把要返回的结果存放到不同于a的局部变量中去,执行完finally之后,在从中取出返回结果,

因此,即使finally中对变量a进行了改变,但是不会影响返回结果。

但是,如果在finally子句中最后添加上return a会怎样呢?

执行结果如下:

Compiling 1 source file to E:/sun/InsideJVM/build/classes
E:/sun/InsideJVM/src/JVMTest.java:37: warning: finally clause cannot complete normally
        }
1 warning
compile-single:
run-single:
abc
a: 2
aa:2

具体的分析可以借助于javap,(为便于分析,注释掉了输出语句):

例如:javap -v JVMTest (没加return a;前)

结果为:


E:/sun/InsideJVM/build/classes>javap -v JVMTest
Compiled from "JVMTest.java"
public class JVMTest extends java.lang.Object
  SourceFile: "JVMTest.java"
  minor version: 0
  major version: 0
  Constant pool:
const #1 = Method       #12.#31;        //  java/lang/Object."<init>":()V
const #2 = Field        #32.#33;        //  java/lang/System.out:Ljava/io/PrintS
tream;
const #3 = class        #34;    //  StringBuffer
const #4 = Method       #3.#31; //  java/lang/StringBuffer."<init>":()V
const #5 = String       #35;    //  aa:
const #6 = Method       #3.#36; //  java/lang/StringBuffer.append:(Ljava/lang/St
ring;)Ljava/lang/StringBuffer;
const #7 = Method       #11.#37;        //  JVMTest.aa:()I
const #8 = Method       #3.#38; //  java/lang/StringBuffer.append:(I)Ljava/lang/
StringBuffer;
const #9 = Method       #3.#39; //  java/lang/StringBuffer.toString:()Ljava/lang
/String;
const #10 = Method      #40.#41;        //  java/io/PrintStream.println:(Ljava/l
ang/String;)V
const #11 = class       #42;    //  JVMTest
const #12 = class       #43;    //  Object
const #13 = Asciz       <init>;
const #14 = Asciz       ()V;
const #15 = Asciz       Code;
const #16 = Asciz       LineNumberTable;
const #17 = Asciz       LocalVariableTable;
const #18 = Asciz       this;
const #19 = Asciz       LJVMTest;;
const #20 = Asciz       main;
const #21 = Asciz       ([Ljava/lang/String;)V;
const #22 = Asciz       args;
const #23 = Asciz       [Ljava/lang/String;;
const #24 = Asciz       aa;
const #25 = Asciz       ()I;
const #26 = Asciz       a;
const #27 = Asciz       I;
const #28 = Asciz       b;
const #29 = Asciz       SourceFile;
const #30 = Asciz       JVMTest.java;
const #31 = NameAndType #13:#14;//  "<init>":()V
const #32 = class       #44;    //  System
const #33 = NameAndType #45:#46;//  out:Ljava/io/PrintStream;
const #34 = Asciz       java/lang/StringBuffer;
const #35 = Asciz       aa:;
const #36 = NameAndType #47:#48;//  append:(Ljava/lang/String;)Ljava/lang/String
Buffer;
const #37 = NameAndType #24:#25;//  aa:()I
const #38 = NameAndType #47:#49;//  append:(I)Ljava/lang/StringBuffer;
const #39 = NameAndType #50:#51;//  toString:()Ljava/lang/String;
const #40 = class       #52;    //  PrintStream
const #41 = NameAndType #53:#54;//  println:(Ljava/lang/String;)V
const #42 = Asciz       JVMTest;
const #43 = Asciz       java/lang/Object;
const #44 = Asciz       java/lang/System;
const #45 = Asciz       out;
const #46 = Asciz       Ljava/io/PrintStream;;
const #47 = Asciz       append;
const #48 = Asciz       (Ljava/lang/String;)Ljava/lang/StringBuffer;;
const #49 = Asciz       (I)Ljava/lang/StringBuffer;;
const #50 = Asciz       toString;
const #51 = Asciz       ()Ljava/lang/String;;
const #52 = Asciz       java/io/PrintStream;
const #53 = Asciz       println;
const #54 = Asciz       (Ljava/lang/String;)V;

{
public JVMTest();
  Code:
   Stack=1, Locals=1, Args_size=1
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return
  LineNumberTable:
   line 21: 0
   line 23: 4
  LocalVariableTable:
   Start  Length  Slot  Name   Signature
   0      5      0    this       LJVMTest;

public static void main(java.lang.String[]);
  Code:
   Stack=3, Locals=1, Args_size=1
   0:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   new     #3; //class StringBuffer
   6:   dup
   7:   invokespecial   #4; //Method java/lang/StringBuffer."<init>":()V
   10:  ldc     #5; //String aa:
   12:  invokevirtual   #6; //Method java/lang/StringBuffer.append:(Ljava/lang/S
tring;)Ljava/lang/StringBuffer;
   15:  invokestatic    #7; //Method aa:()I
   18:  invokevirtual   #8; //Method java/lang/StringBuffer.append:(I)Ljava/lang
/StringBuffer;
   21:  invokevirtual   #9; //Method java/lang/StringBuffer.toString:()Ljava/lan
g/String;
   24:  invokevirtual   #10; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
   27:  return
  LineNumberTable:
   line 25: 0
   line 26: 27
  LocalVariableTable:
   Start  Length  Slot  Name   Signature
   0      28      0    args       [Ljava/lang/String;

public static int aa();
  Code:
   Stack=1, Locals=4, Args_size=0
   0:   iconst_1
   1:   istore_0
   2:   bipush  10
   4:   istore_1
   5:   iload_0
   6:   istore_2
   7:   iconst_2
   8:   istore_0
   9:   iload_2
   10:  ireturn
   11:  astore_3
   12:  iconst_2
   13:  istore_0
   14:  aload_3
   15:  athrow
  Exception table:
   from   to  target type
     5     7    11   any
    11    12    11   any
  LineNumberTable:
   line 28: 0
   line 29: 2
   line 32: 5
   line 34: 7
  LocalVariableTable:
   Start  Length  Slot  Name   Signature
   2      14      0    a       I
   5      11      1    b       I

}


E:/sun/InsideJVM/build/classes>

从第5,6可知,执行return前,已经把结果准备好了,并存到了第二个局部变量(不是第0个:a)中。

加入return a;之后的情形可类似分析,此处略之。

原创粉丝点击