有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

带循环变量的java作用域

今天,我们在工作中讨论了以下两个函数中哪一个性能更好,内存消耗更少,并且不强调gc

public class Main {

    public void do1() {
        int result = 0;
        int val;
        do {
            val = calc(result);
            result = val * 2;
        } while (result < 1000);
    }

    public void do2() {
        int result = 0;
        do {
            final int val = calc(result);
            result = val * 2;
        } while (result < 1000);
    }

    private int calc(final int i) {
        return i + 2;
    }
}

在我看来,两者都是等价的,无论val是在循环内部还是外部定义的。我唯一想到的是变量的范围应该尽可能地缩小。但是,在讨论gc如何处理这些情况时,我们没有找到解决方案

我们看了字节码,没有区别

Compiled from "Main.java"
public class Main {
  public Main();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public void do1();
    Code:
       0: iconst_0
       1: istore_1
       2: aload_0
       3: iload_1
       4: invokespecial #2                  // Method calc:(I)I
       7: istore_2
       8: iload_2
       9: iconst_2
      10: imul
      11: istore_1
      12: iload_1
      13: sipush        1000
      16: if_icmplt     2
      19: return

  public void do2();
    Code:
       0: iconst_0
       1: istore_1
       2: aload_0
       3: iload_1
       4: invokespecial #2                  // Method calc:(I)I
       7: istore_2
       8: iload_2
       9: iconst_2
      10: imul
      11: istore_1
      12: iload_1
      13: sipush        1000
      16: if_icmplt     2
      19: return
}

有人知道这里是否真的没有区别,或者可以解决讨论吗


共 (2) 个答案

  1. # 1 楼答案

    没有区别。由于没有分配new对象,因此这两个对象都与垃圾收集器没有任何交互int变量在堆栈上分配

    这反映在每个相同的字节码中

  2. # 2 楼答案

    正如您在检查字节码时所看到的,Java中没有任何区别。您可能会在其他语言中看到一些差异,例如,如果用C编写相同的代码

    所以在你的例子中,争论是关于化妆品和可维护性的

    我认为使用最具体的作用域级别(如do2)更好,如下所示:

    • 它改进了所需变量的局部性
    • 它使重构时代码块的提取更容易
    • 对于更复杂的示例确实会产生不同的字节码,并且在循环中分配变量的成本不太高(例如,对于大型复合对象,您可能不希望这样做)的情况,这是一个好习惯

    不同的观点,但在您的示例中,我甚至认为可以在下一个表达式中内联val变量。不这样做只会增加噪音。但我假设这样做是为了示例或打印值