为什么传递给runnable的变量需要是最终的?

11 java variables final runnable

如果我有一个变量int x = 1,比如说,我在主线程中声明了一个runnable,并且我想将x传递给runnable的run()方法,那么必须声明它final.为什么?

final int x = 0;//<----must be final...
private class myRun implements Runnable {

    @Override
    public void run() {
        x++;//
    }

}
Run Code Online (Sandbox Code Playgroud)

jac*_*obm 10

因为这就是语言规范所说的.根据Guy Steele的说法,这个选择背后的基本原理是程序员会期望int x = 0一个方法中的声明导致堆栈分配存储,但是如果你可以new myRun()从方法中返回一个(或者让一个myRun持久化的函数返回)并且你之后可以对其进行修改,然后x必须进行堆分配,以获得您期望的语义.

他们本可以做到这一点,事实上其他语言就是这样做的.但是Java设计者决定要求你标记xfinal避免要求实现堆分配看起来像堆栈分配的存储.

(我应该注意:这不是特定于Runnable.它适用于任何匿名内部类.)


Joh*_*ohn 10

因为如果它们能够被改变,它可能会导致很多问题,请考虑这个:

public void count()
{
    int x;

    new Thread(new Runnable()
    {
        public void run()
        {
            while(x < 100)
            {
                x++;
                try
                {
                    Thread.sleep(1000);
                }catch(Exception e){}
            }
        }
     }).start();

     // do some more code...

     for(x = 0;x < 5;x++)
         for(int y = 0;y < 10;y++)
             System.out.println(myArrayElement[x][y]);
 }
Run Code Online (Sandbox Code Playgroud)

这是一个粗略的例子,但你可以看到可能发生很多无法解释的错误.这就是变量必须是最终的原因.以下是针对上述问题的简单修复:

public void count()
{
    int x;

    final int w = x;

    new Thread(new Runnable()
    {
        public void run()
        {
            int z = w;

            while(z < 100)
            {
                z++;
                try
                {
                    Thread.sleep(1000);
                }catch(Exception e){}
            }
        }
     }).start();

     // do some more code...

     for(x = 0;x < 5;x++)
         for(int y = 0;y < 10;y++)
             System.out.println(myArrayElement[x][y]);
 } 
Run Code Online (Sandbox Code Playgroud)

如果你想要一个更完整的解释,它有点像同步.Java希望阻止您从多个线程引用一个Object.这里有一点关于同步:

希望这有帮助!