简体   繁体   中英

Variable visibility in Java

In the following code, why can't I see the variable "i" from another thread?

public class Main {
    public static void main(String[] args) {
        int i = 0;
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(i);
            }
        }).start();
    }
}

And why can I see it in the code below?

public class Main {
    int i = 0;      
    public static void main(String[] args) {
        new Main().method();
    }

    private void method() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                i = 1;
            }
        }).start();
    }
}

From docs :

As with instance methods and variables, an inner class is associated with an instance of its enclosing class and has direct access to that object's methods and fields.

在此输入图像描述

Now taking the second example first, when i is declared in parent class, the inner class can access it, because inner class has access to entire parent object. And i is correctly referenced as Main.this.i from inner class.Now compiler secretly makes a copy of this.i inside inner class. this never changes inside the object, this.i will point to correct object for both inner and outer class. Compiler is happy.

In first example, i is not part of parent class, its declared inside a method hence its reference is now on stack , and not on heap. (In this case, i doesn't get to live on that big outer circle shown in above diagram). Now compiler must secretly make a copy of i inside inner class as well. But it is afraid that method's i may change on stack. Compiler can't use outer class connection to get to i here, and it can't bother to copy i reference from stack every time it changes. So, it is decided that you must make the method's i reference unchangeable, or in other words, final .

The obscure secret tricks Java plays so that you can access outer fields from inner classes is explained in detail here: http://techtracer.com/2008/04/14/mystery-of-accessibility-in-local-inner-classes/

and discussed more "why's" here : http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg04044.html

tl;dr: Instance fields are directly accessible by inner classes, local fields must be made final to be accessible by a inner class.

Java only allows you to access the values of local variables that are declared final in anonymous classes. No writing is allowed. The rationale for this is because the function scope might be (and indeed in this case is) exited while the variable is accessible from within the inner class, the value is actually cached within the anonymous class instances. To avoid confusion and make JIT work, these variables are allowed to be final only. Notice that only the primitive value, or the reference cannot be modified, but anything contained within a referenced object can still be modified.

In the second case it is an instance variable accessible to the thread. Note that i = 1 stands now for Main.this.i ; the Main.this. part being implicit.

In the first program you can "see" variable i , but not access it, because it is not declared final . Only member variables and final local variables declared before creating an instance of your anonymous class can be accessed:

public class Main {
    public static void main(String[] args) {
        final int i = 123; // Make the variable final
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(i); // Now it works, but you cannot assign it
            }
        }).start();
    }
}

Demo on ideone .

Making your variable static would work as well:

public class Main {
    private static int i = 321;
    public static void main (String[] args) throws java.lang.Exception
    {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(i); // Now it works, but you cannot assign it
            }
        }).start();
    }
}

Demo.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM