简体   繁体   English

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

[英]Why do variables passed to runnable need to be final?

If I have a variable int x = 1 , say, and I declare a runnable in the main thread, and I want to pass x to the runnable's run() method, it must be declared final . 如果我有一个变量int x = 1 ,比如说,我在主线程中声明了一个runnable,并且我想将x传递给runnable的run()方法,那么它必须被声明为final Why? 为什么?

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

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

}

Because that's what the language specification says. 因为这就是语言规范所说的。 According to Guy Steele , the rationale behind this choice is that programmers would expect the declaration int x = 0 in a method to result in stack-allocated storage, but if you can return a new myRun() from the method (or otherwise let a myRun persist past the function's return) and you can modify it afterwards, then x has to be heap-allocated instead to have the semantics you'd expect. 根据Guy Steele的说法 ,这个选择背后的基本原理是程序员会期望一个方法中的声明int x = 0导致堆栈分配的存储,但是如果你可以从方法返回一个new myRun() (或者让一个myRun持续超过函数的返回值,然后你可以修改它,然后x必须被堆分配而不是你期望的语义。

They could have done that, and in fact other languages have done it that way. 他们本可以做到这一点,事实上其他语言就是这样做的。 But the Java designers decided instead to require that you mark x as final to avoid requiring implementations to heap-allocate what looks like stack-allocated storage. 但是Java设计者决定要求你将x标记为final以避免要求实现堆分配看起来像堆栈分配的存储。

(I should note: this isn't specific to Runnable . It applies to any anonymous inner class.) (我应该注意:这不是特定于Runnable 。它适用于任何匿名内部类。)

Because if they are able to be changed, it could cause a lot of problems, consider this: 因为如果它们能够被改变,它可能会导致很多问题,请考虑这个:

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

This is a rough example but you can see where a lot of unexplained errors could occur. 这是一个粗略的例子,但你可以看到可能发生很多无法解释的错误。 This is why the variables must be final. 这就是变量必须是最终的原因。 Here is a simple fix for the problem above: 以下是针对上述问题的简单修复:

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

If you want a more full explanation, it is sort of like synchronized. 如果你想要一个更完整的解释,它有点像同步。 Java wants to prevent you from referencing one Object from multiple Threads. Java希望阻止您从多个线程引用一个Object。 Here is a little bit about synchronization: 这里有一点关于同步:

Hope this helped! 希望这有帮助!

The big 'issue' with multithreading, and also the entire reason for using it, is that multiple things are happening at the same time. 多线程的大问题以及使用它的全部原因是多个事情同时发生。 All of a sudden, the value of any variable that your thread accesses that isn't local to the thread can change at any point. 突然之间,线程访问的任何不是线程本地的变量的值都可以在任何时候改变。 Thus, you may thing you're just printing the numbers 1-10 with this code: 因此,您可能只需使用以下代码打印数字1-10:

int x = 0;  //supposing that this was allowed to be non-final...
   private class myRun implements Runnable{

    @Override
    public void run() {
        for (int i=0; i<10; i++ ) {
            System.Out.Println( x++ );
        }
    }
}

But in reality, if other code in that class changes the value of x, you could end up printing 230498 - 230508. The value of x could event change in the middle of your loop. 但实际上,如果该类中的其他代码更改了x的值,则最终可能会打印230498 - 230508.x的值可能会在循环中间发生事件更改。 If you can't rely on x having a certain value or keeping a value you assigned to it previously, it becomes futile to use it in your code. 如果您不能依赖具有特定值的x或保留之前分配给它的值,则在代码中使用它将变得徒劳无功。 Why would you use a variable if its contents could change at the drop of a hat? 如果变量的内容可能会随着帽子的变化而变化,为什么还要使用变量?

Rather than just forbidding you to use it at all, Java requires that you make it final . Java要求你让它成为final ,而不是仅仅禁止你使用它。 You could just 'promise' to never change the value of x from another thread, but then why not make it final in the first place and let the compiler help you out? 您可以“承诺”永远不会从另一个线程更改x的值,但为什么不首先让它成为final并让编译器帮助您? Granted, you can only access the initial value assigned to x , but just being able to access the variable's initial value is better than not being able to use it at all, which would effectively cut off the thread's ability to utilize the data from the rest of your class. 当然,你只能访问分配给x的初始值,但只是能够访问变量的初始值比完全不能使用它更好,这将有效地切断线程利用其余数据的能力。你的班级

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在java中,为什么需要将闭包变量声明为final? - in java, why do closured variables need to be declared final? 为什么我们需要一个Runnable来启动线程? - Why do we need a Runnable to start threads? 我是否需要为 Java 中的所有不可变变量指定 «final» 修饰符? - Do I need to specify «final» modifier for ALL immutable variables in Java? 在声明最终变量后是否需要立即给它们赋值 - Do final variables need to be given a value immediately after declaring them 为什么局部变量是最终变量? - Why local variables are final? 为什么jdk需要使用“final”来创建“Semaphore”的对象? - Why do jdk need to use "final" to create object of "Semaphore"? java @SafeVarargs 为什么私有方法需要是 final - java @SafeVarargs why do private methods need to be final 可运行的“从内部类引用的局部变量中的计数器必须是最终的或有效地是最终的” - counter in runnable 'local variables referenced from an inner class must be final or effectively final' 为什么我需要有一个runnable而不是直接从main调用? - Why do I need to have a runnable instead of calling directly from main? 为什么java接口变量是final的? - Why the java interface variables are final?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM