为什么在java字节码中重复一些指令?

时间:2014-03-23 16:13:48

标签: java bytecode

Java代码如下所示:

File f1 = File.createTempFile("example", ".txt");
File f2 = File.createTempFile("outExample", ".txt");        
FileInputStream in = new FileInputStream(f1);
FileOutputStream out = new FileOutputStream(f2);
try {
    int c;
    while ((c = in.read()) != -1) {
             out.write(c);
    }
} 
finally {
    if (in != null) {
        in.close();
    }
    if (out != null) {
        out.close();
    }
}       
return f1.delete() && f2.delete();

和字节码:

TRYCATCHBLOCK L0 L1 L1 
   L2
    LINENUMBER 138 L2
    LDC "example"
    LDC ".txt"
    INVOKESTATIC File.createTempFile (String, String) : File
    ASTORE 1
   L3
    LINENUMBER 139 L3
    LDC "outExample"
    LDC ".txt"
    INVOKESTATIC File.createTempFile (String, String) : File
    ASTORE 2
   L4
    LINENUMBER 141 L4
    NEW FileInputStream
    DUP
    ALOAD 1: f1
    INVOKESPECIAL FileInputStream.<init> (File) : void
    ASTORE 3
   L5
    LINENUMBER 142 L5
    NEW FileOutputStream
    DUP
    ALOAD 2: f2
    INVOKESPECIAL FileOutputStream.<init> (File) : void
    ASTORE 4
   L0
    LINENUMBER 146 L0
    GOTO L6
   L7
    LINENUMBER 147 L7
    ALOAD 4: out
    ILOAD 5: c
    INVOKEVIRTUAL FileOutputStream.write (int) : void
   L6
    LINENUMBER 146 L6
    ALOAD 3: in
    INVOKEVIRTUAL FileInputStream.read () : int
    DUP
    ISTORE 5
   L8
    ICONST_M1
    IF_ICMPNE L7
   L9
    LINENUMBER 149 L9
    GOTO L10
   L1
    LINENUMBER 150 L1
    ASTORE 6
   L11
    LINENUMBER 151 L11
    ALOAD 3: in
    IFNULL L12
   L13
    LINENUMBER 152 L13
    ALOAD 3: in
    INVOKEVIRTUAL FileInputStream.close () : void
   L12
    LINENUMBER 154 L12
    ALOAD 4: out
    IFNULL L14
   L15
    LINENUMBER 155 L15
    ALOAD 4: out
    INVOKEVIRTUAL FileOutputStream.close () : void
   L14
    LINENUMBER 157 L14
    ALOAD 6
    ATHROW
   L10
    LINENUMBER 151 L10
    ALOAD 3: in
    IFNULL L16
   L17
    LINENUMBER 152 L17
    ALOAD 3: in
    INVOKEVIRTUAL FileInputStream.close () : void
   L16
    LINENUMBER 154 L16
    ALOAD 4: out
    IFNULL L18
   L19
    LINENUMBER 155 L19
    ALOAD 4: out
    INVOKEVIRTUAL FileOutputStream.close () : void
   L18
    LINENUMBER 159 L18
    ALOAD 1: f1
    INVOKEVIRTUAL File.delete () : boolean
    IFEQ L20
    ALOAD 2: f2
    INVOKEVIRTUAL File.delete () : boolean
    IFEQ L20
    ICONST_1
    IRETURN
   L20
    ICONST_0
    IRETURN

有人可以告诉我为什么每个流(L13和L17,L15和L19)调用两次close()指令?如果没有finally块,但是使用try-catch,在字节码中每个流只调用一个close()。

1 个答案:

答案 0 :(得分:5)

Ones适用于隐式捕获异常且需要重新抛出的情况(请注意最后的ATHROW

L15
 LINENUMBER 155 L15
 ALOAD 4: out
 INVOKEVIRTUAL FileOutputStream.close () : void
L14
 LINENUMBER 157 L14
 ALOAD 6
 ATHROW

另一个没有抛出异常的时候:

L19
 LINENUMBER 155 L19
 ALOAD 4: out
 INVOKEVIRTUAL FileOutputStream.close () : void

如果你看顶部,你会看到

TRYCATCHBLOCK L0 L1 L1 

这些标签类似于在哪里跳跃捕获以及在哪里跳转到最后。 Catch将抛出的异常留在堆栈的顶部(同样,ATHROW)。检查堆栈以查看顶级成员是否是异常是比复制代码更昂贵(更难/不可能;堆栈没有打字)。