【问题标题】:creating final variables inside a loop在循环中创建最终变量
【发布时间】:2009-03-04 07:48:31
【问题描述】:

这在java中是否允许:

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

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

它们是否是两个完全不同的变量,只是名称相同 - 上一次循环运行中的变量已经朝着垃圾收集器的方向前进?

【问题讨论】:

    标签: java final


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        【解决方案3】:

        变量只是堆栈上的一个位置。尝试将变量保持在尽可能小的范围内,并尝试使它们成为最终变量。然而,范围和最终只是源代码的东西......从代码生成/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
        
        }
        

        【讨论】:

          【解决方案4】:

          回答是,是的,您确实可以将循环中的变量标记为“最终”。这是这样做的效果(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.
          
          }
          

          【讨论】:

            【解决方案5】:

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

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

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

            公开课测试{

            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);
                }
            }
            

            }

            如果我错了,请纠正我。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-05-13
              • 2020-01-16
              • 1970-01-01
              相关资源
              最近更新 更多