代码之家  ›  专栏  ›  技术社区  ›  marcin

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

  •  4
  • marcin  · 技术社区  · 12 年前

    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
    

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

    1 回复  |  直到 12 年前
        1
  •  5
  •   David Ehrmann    12 年前

    一种是指异常被隐式捕获并需要重新处理的情况(注意 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)。检查堆栈以查看顶层成员是否为异常比复制代码要昂贵得多(而且很难/不可能;堆栈没有类型化)。