From the JVM instruction level, try-catch-finally return value problem

From the JVM instruction level, try-catch-finally return value problem

 

It seems that many people are confused about the return value of the following method:

package cc.lixiaohui.demo;  
  
public class ReturnValueTest {  
    public int test() {  
        int a;  
        try {  
            a = 1;  
            //int b = 1 / 0;  
            return a;  
        } catch (Exception e) {  
            a = 2;  
            return a;  
        } finally {  
            a = 3;  
        }  
    }  
}

 

The return value of the test method is naturally 1. If the commented line is removed, it will be 2.

 

Why?

View the bytecode with javap -verbose ReturnValueTest:

Focus on the test() method directive:

Compiled from "ReturnValueTest.java"
public class cc.lixiaohui.demo.ReturnValueTest extends java.lang.Object
  SourceFile: "ReturnValueTest.java"
  minor version: 0
  major version: 49		
  Constant pool: --constant pool
const #1 = class        #2;     //  cc/lixiaohui/demo/ReturnValueTest
const #2 = Asciz        cc/lixiaohui/demo/ReturnValueTest;
const #3 = class        #4;     //  java/lang/Object
const #4 = Asciz        java/lang/Object;
const #5 = Asciz        <init>;
const #6 = Asciz        ()V;
const #7 = Asciz        Code;
const #8 = Method       #3.#9;  //  java/lang/Object."<init>":()V
const #9 = NameAndType  #5:#6;//  "<init>":()V
const #10 = Asciz       LineNumberTable;
const #11 = Asciz LocalVariableTable;
const #12 = Asciz       this;
const #13 = Asciz       Lcc/lixiaohui/demo/ReturnValueTest;;
const #14 = Asciz       test;
const #15 = Asciz       ()I;
const #16 = class       #17;    //  java/lang/Exception
const #17 = Asciz       java/lang/Exception;
const #18 = Asciz       a;
const #19 = Asciz       I;
const # 20 = Asciz and;
const #21 = Asciz       Ljava/lang/Exception;;
const #22 = Asciz       SourceFile;
const # 23 = Asciz ReturnValueTest.java;

{
public cc.lixiaohui.demo.ReturnValueTest(); --The construction method will not be analyzed
  Code:
   Stack=1, Locals=1, Args_size=1
   0:   aload_0
   1:   invokespecial   #8; //Method java/lang/Object."<init>":()V
   4:   return
  LineNumberTable:
   line 8: 0

  LocalVariableTable:
   Start  Length  Slot  Name   Signature
   0      5      0    this       Lcc/lixiaohui/demo/ReturnValueTest;


public int test();
  Code:
   Stack=1, Locals=5, Args_size=1 -- [Stack=1 seems to indicate that the stack depth is 1,]Locals=5 indicates that the length of the local variable table is 5, and Args_size=1 indicates that the method has 1 parameter (this)
   0: iconst_1 -- push the int value 1 onto the stack
   1: istore_1 -- pop the top value of the stack (ie 1) and save it to the second position of the local variable table (the subscript of the local variable table starts from 0, but the 0 position is occupied by the this variable)
   2: iload_1 -- push the value of the second position of the local variable table onto the stack
   3: istore 4 -- pop the value on the top of the stack and save it to the 5th position of the local variable table (you can see it here)
   5: iconst_3 -- (the finally block starts here) push the int value 3 onto the stack
   6: istore_1 -- pop the value at the top of the stack (ie 3) and store it in the second position of the local variable table
   7: iload 4 -- pushes the fifth position (ie 1) of the local variable table onto the stack
   9: ireturn -- return the value at the top of the stack (ie 1), end the method call (the path is try (no exception thrown) -> finally)
   
   10: astore_2 -- store the reference to the top of the stack (here, the exception e caught in the catch block) to the third position of the local variable table
   11: iconst_2 -- push the int value 2 onto the stack
   12: istore_1 -- pop and store the top value of the stack (ie 2) to the second position of the local variable table
   13: iload_1 -- push the value of the second position of the local variable table (ie 2) onto the stack
   14: istore 4 -- pop the top value of the stack (ie 2) and save it to the fifth position of the local variable table. The fifth position was originally 1, but now 1 is overwritten and becomes 2
   16: iconst_3 -- (the finally block starts here) push the int value 3 onto the stack
   17: istore_1 -- pop the value at the top of the stack (ie 3) and store it to the second position of the local variable table
   18: iload 4 -- pushes the fifth position (ie 2) of the local variable table onto the stack
   20: ireturn -- return the value at the top of the stack (ie 2), end the method call (the path is try (throw Exception or its subclass exception) -> catch -> finally)
   
   21: astore_3 -- store the reference to the top of the stack (here is a non-Exception subclass exception) to the fourth position of the local variable table
   22: iconst_3 -- push the int value 3 onto the stack
   23: istore_1 -- pop and store the top value of the stack (ie 3) to the second position of the local variable table
   24: aload_3 -- push the fourth position of the local variable table (that is, the exception reference) on the stack
   25: athrow -- throw the exception at the top of the stack (the path is try (throw non-Exception or its subclass exception) -> finally, or try (throw Exception or its subclass exception) -> catch (throw any exception) -> finally )
  Exception table:
   from   to  target type
     0 5 10 Class java/lang/Exception -- If the execution reaches lines 0-5 (that is, in the try block) and throws java.lang.Exception or its subclasses, jump to line 10 for execution (ie, the catch block)
     0 5 21 any -- if execution reaches lines 0-5 (ie, in the try block), a non-java.lang.Exception or its subclass is thrown, and then jumps to line 21 for execution (ie, the finally block)
    10 16 21 any -- if any exception is thrown to line 10-16 (that is, in the catch block), jump to line 21 for execution (that is, the finally block)
  LineNumberTable: --This table is the mapping between the number of source code lines and the number of bytecode lines
   line 13: 0
   line 14: 2
   line 19: 5
   line 14: 7
   line 15: 10
   line 16: 11
   line 17: 13
   line 19: 16
   line 17: 18
   line 18: 21
   line 19: 22
   line 20: 24

  LocalVariableTable: --This is the local variable table. The combination of start and length can determine the scope of the variable. For example, the scope of this is the entire method.
   Start  Length  Slot  Name   Signature
   0 26 0 this Lcc/lixiaohui/demo/ReturnValueTest; -- occupy the first slot (a slot should be 32bits)
   2 8 1 a I --I identifies int, occupying the second slot
   13 8 1 a I -- occupy the second slot
   24 2 1 a I -- occupy the second slot
   11 10 2 e Ljava/lang/Exception; -- occupy the third slot


}

 

It can be found that the jvm always puts the return value in the position of the last local variable table, and changing x in finally does not affect the return value.

 

refer to:

JVM stack frame

http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326190315&siteId=291194637