52

这在java中是否允许:

for(int i=0;i<5;i++){
  final int myFinalVariable = i;
}

我的问题的关键字是final。是否允许做一个随着循环的每次运行而改变的最终变量?我想知道这一点,因为 final 说您不能更改变量的值(仅调用myFinalVariable = i),但我正在重新定义整个变量final int

它们是两个完全不同的变量,只是同名吗?循环上一次运行的变量已经在通往垃圾收集器的路上了?

4

5 回答 5

89

是的,这是允许的。final关键字意味着您不能在其范围内更改变量的。对于您的循环示例,您可以认为变量在循环底部超出范围,然后在循环顶部以新值返回范围。分配给循环内的变量将不起作用。

于 2009-03-04T07:49:57.377 回答
12

您是对的,对于循环中的每次迭代,您都在创建一个新变量。这些变量确实共享相同的名称,但这很好,因为它们不在同一个范围内。下一个示例不起作用

final int myFinalVariable = 0;
for(int i=0;i<5;i++){
  myFinalVariable = i;
}
于 2009-03-04T07:54:34.323 回答
9

变量只是堆栈上的一个位置。尝试将变量保持在尽可能小的范围内,并尝试使它们成为最终变量。然而,范围和最终只是源代码的东西......从代码生成/VM的角度来看,它们根本不重要。

在您的具体示例中,使用“int”不会创建垃圾。但是,如果创建的是对象,那么对于这两种情况,垃圾的数量和垃圾何时有资格进行清理将是相同的。

采取以下代码:

public class X
{
    public static void main(final String[] argv)
    {
        foo();
        bar();
    }

    private static void foo()
    {
        for(int i=0;i<5;i++)
        {
            final int myFinalVariable = i;
        }
    }

    private static void bar()
    {
        for(int i=0;i<5;i++)
        {
            int myFinalVariable = i;
        }
    }
}

编译器为每种方法生成相同的字节码:

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

public static void main(java.lang.String[]);
  Code:
   0:   invokestatic    #2; //Method foo:()V
   3:   invokestatic    #3; //Method bar:()V
   6:   return

private static void foo();
  Code:
   0:   iconst_0
   1:   istore_0
   2:   iload_0
   3:   iconst_5
   4:   if_icmpge       15
   7:   iload_0
   8:   istore_1
   9:   iinc    0, 1
   12:  goto    2
   15:  return

private static void bar();
  Code:
   0:   iconst_0
   1:   istore_0
   2:   iload_0
   3:   iconst_5
   4:   if_icmpge       15
   7:   iload_0
   8:   istore_1
   9:   iinc    0, 1
   12:  goto    2
   15:  return

}

由于声明变量的顺序,添加另一个在循环外声明变量的方法会为您提供稍微不同的字节码)。请注意,此版本不能将变量设为最终版本。最后一个版本不是最好的方法(如果可以的话,循环内的最终变量是最好的):

private static void car()
{
    int myFinalVariable;

    for(int i=0;i<5;i++)
    {
        myFinalVariable = i;
    }
}

private static void car();
  Code:
   0:   iconst_0
   1:   istore_1
   2:   iload_1
   3:   iconst_5
   4:   if_icmpge       15
   7:   iload_1
   8:   istore_0
   9:   iinc    1, 1
   12:  goto    2
   15:  return

}
于 2009-03-04T08:00:26.433 回答
3

正如回答的那样,是的,您确实可以将循环中的变量标记为“最终”。这是这样做的效果(Java 7、Eclipse Indigo、Mac OS X Lion)。

for ( int i = 0; i < 5; i++ ) {

  // With 'final' you cannot assign a new value.
  final int myFinalVariable = i;  // Gets 0, 1, 2, 3, or 4 on each iteration.
  myFinalVariable = 7; // Compiler error: The final local variable myFinalVariable cannot be assigned.

  // Without 'final' you can assign a new value.
  int myNotFinalVariable = i;  // Gets 0, 1, 2, 3, or 4 on each iteration.
  myNotFinalVariable = 7; // Compiler is OK with re-assignment of variable's value.

}
于 2012-04-30T08:48:41.270 回答
2

在循环内声明的变量仅在循环的单次执行之前具有作用域。

在循环内将变量声明为 final 对循环内的变量没有任何影响,但是如果我们在循环外使用 final 修饰符声明变量,则分配给原始类型的值或分配给引用变量的 Object 不能更改。

在下面的示例中,前两个循环没有问题,两个循环都给出相同的输出,但第三个循环给出了编译时错误。

公共类测试{

public static void main(String[] args) {
    for (int i = 0; i < 5; i++) {
        final int j= i;
        System.out.println(j);
    }
    for (int i = 0; i < 5; i++) {
        int j= i;
        System.out.println(j);
    }

    final int j;
    for (int i = 0; i < 5; i++) {
        j= i;
        System.out.println(j);
    }
}

}

如果我错了,请纠正我。

于 2013-07-07T11:56:19.850 回答