变量在循环块中声明

0 java

class Sample {

    int a;

    public void abcx() {
        for (int i = 0; i < 5; i++) {
            if (i % 2 == 0) {
                int b = i;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

多久b分配一次?

Mar*_*oma 7

请看看nhahtdh的回答.这很好,因为它引用了JLS的相关部分.

我不删除这个答案,因为我希望它能为您提供一些提示,以便您自己解决未来问题的答案(或至少是好的猜测).它还可能为您的示例代码提供一些其他说明.

首先:如果谈到"在XYZ情况下Java会做什么",你应该经常问"我的JVM在XYZ情况下做了什么".如果您想回答有关Java本身的问题,您应该能够参考Java语言规范.

编辑:有关此参考,请参阅nhahtdh答案.

您的示例代码中会发生什么?

我猜你可以做的最好的猜测是Java Bytecode.现在加载对象/数据结构/基元类型和分配一个类型之间存在差异.

分配对象意味着您可以为其提供一些可以存储的空间.它只是一个占位符.要加载aload_0意味着对象引用被推送到操作数堆栈上.下一个操作将从操作数堆栈中获取其操作数.

javac Sample.java
javap -c Sample.class
Run Code Online (Sandbox Code Playgroud)

给你Java字节码:

Compiled from "Sample.java"
class Sample {
  int a;

  Sample();
    Code:
       0: aload_0    // load int a
       1: invokespecial #1  // Method java/lang/Object."<init>":()V (every class is a child class of Object)
       4: return        

  public void abcx();
    Code:
       0: iconst_0      // get 0 on stack
       1: istore_1      // store 0 to variable 1 (int i=0)
       2: iload_1       // load 0 from variable 1 (load 0 from i)
       3: iconst_5      // load 5 from
       4: if_icmpge     21 // i<5 (21 means: jump to line 21 if i >= 5)
       7: iload_1       // load i
       8: iconst_2      // load 2
       9: irem          // i%2
      10: ifne          15 // if(i%2!=0) jump to line 15
      13: iload_1       // load i
      14: istore_2      // b=i
      15: iinc          1, 1 // i++
      18: goto          2 // back to loop condition
      21: return        
}
Run Code Online (Sandbox Code Playgroud)
  • aload_0:在操作数堆栈上加载对象引用(源代码)
  • iconst_n:这些用于将常量0到5推入堆栈.(来源)
  • istore_1:将堆栈顶部的整数存储到变量1中
  • invokespecial :( 来源)
  • if_icmpge:从堆栈中弹出前两个整数并进行比较.如果value2大于或等于value1,则执行转移到地址()
  • irem:从操作数堆栈中弹出两个整数,将value2除以value1(即value2/value1),计算余数并将int余数推回堆栈()

回答你的分配问题

我不确定答案是否正确.我猜用户Budda可能是对的: 编辑:不,Budda错了.但让我们解释为什么这是一个很好的猜测.

当i为0时分配一次,然后当i为2时再分配,当i为4时分配.因此总共为3.

一旦}关闭,范围b就结束了.因此它应该被垃圾收集器"删除",因为b它没有参考.但是你必须考虑原始数据类型不在堆上,只有堆由垃圾收集器()管理.

当您查看上面的字节代码时,您可能会注意到b仅在一行(istore_2)中更改.所以你可能想看看进程的内存布局.

我不确定Java程序是否也适用,但x86中的进程也是如此.进程在内存中看起来像这样:

在此输入图像描述 来源:我的博客 :-)这是一个操作系统类的分配.

您可以看到原始数据类型在内存布局中有自己的部分.所以我猜它在加载类时会被分配一次.但我不能给你这个猜测的来源,我不确定.

编辑:另请参阅Java虚拟机的体系结构.

  • +1表示看看.一个更好的答案将包括对像我这样无法快速阅读javap输出的人的解释. (3认同)
  • 这里没有显示"分配".字节码仅显示正在加载或存储的局部变量. (3认同)