java - 在循环 block 中声明变量

标签 java

class Sample {

    int a;

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

多久分配一次b

最佳答案

请看一下 nhahtdh 的回答。很好,因为它引用了 JLS 的相关章节。

我不会删除这个答案,因为我希望它能给你一些提示,让你自己找到这样的答案(或者至少是好的猜测),以应对 future 的问题。它还可能为您的示例代码提供一些额外的解释。

首先:如果涉及到“Java 在 XYZ 情况下会做什么”,您应该经常问“我的 JVM 在 XYZ 情况下会做什么”。如果你想回答有关Java本身的问题,应该可以引用Java Language Specification

编辑:请参阅 nhahtdh 答案以获取此引用。

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

我想您能做出的最佳猜测是使用 Java 字节码。现在,加载对象/数据结构/基本类型和分配对象/数据结构/基本类型之间存在差异。

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

javac Sample.java
javap -c Sample.class

给你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        
}
  • aload_0:在操作数堆栈上加载对象引用 ( source )
  • iconst_n:这些用于将常量整数 0 到 5 压入堆栈。 (source)
  • istore_1 :将栈顶的整数存入变量1
  • 调用特殊:( source )
  • if_icmpge :将顶部的两个整数从堆栈中弹出并进行比较。如果 value2 大于或等于 value1,则执行分支到地址 ( source )
  • irem:从操作数堆栈中弹出两个 int,将 value2 除以 value1(即 value2/value1),计算余数并将 int 余数推回堆栈 ( source )

回答您的分配问题

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

It is allocated once when i is 0, and then when i is 2 and again when i is 4. So 3 in total.

一旦}关闭,b的范围就结束了。因此它应该被垃圾收集器“删除”,因为b没有对它的引用。但你必须考虑到primitive data types不在堆上,只有堆由垃圾收集器管理 ( source )。

当您查看上面的字节代码时,您可能会注意到 b 仅在一行中发生了更改 (istore_2)。因此,您可能想查看进程的内存布局。

我不确定以下内容是否也适用于 Java 程序,但适用于 x86 中的进程。进程在内存中看起来像这样:

enter image description here 来源:My blog :-) 这是操作系统类的作业。

您可以看到原始数据类型在内存布局中有自己的部分。所以我想它会在类加载时分配一次。但我无法向您提供这一猜测的来源,而且我对此也不确定。

编辑:另请参阅The Architecture of the Java Virtual Machine .

关于java - 在循环 block 中声明变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16314417/

相关文章:

java - 使用 "Eclipse IDE for Java EE Developers"包修复 ClosedFileSystemException 错误

java - JSTL:绝对 uri:http://java.sun.com/jsp/jSTL/core 无法在 web.xml 或随此应用程序部署的 jar 文件中解析

java - 从 R.raw 文件夹中打开文件

java - 虚拟 log4j 配置(用于测试)

java - 如何在删除 fragment 时动态更新ViewPager

java - 在两个 Activity 之间旋转设备时出现 configChanges 问题 [+VIDEO]

java - 无法错误 : unable to get cib

java - 嵌套循环将索引值提取到新数组中

java - 显示对象数组的结果

java - 卡夫卡宕机时发送消息时没有异常