Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variable visibility in Java

Tags:

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();     } } 
like image 784
Alex Avatar asked Aug 24 '13 09:08

Alex


People also ask

What is visibility of variables in Java?

1) Any variable declared in a method is only visible in that method. (method-local). The programmer has no choice in that. 2) Any variable declared with the modifier private is visible only from within instances of the class it is delared in. 3) public variables can be accessed from any class with object.

What refers to the visibility of variable?

Visibility of a variable is defined as if a variable is accessible or not inside a particular region of code or the whole program.

What determines the visibility of variables and methods?

By default, the variables and methods of a class are accessible to members of the class itself and to other classes in the same package. To borrow from C++ terminology, classes in the same package are friendly. We'll call this the default level of visibility.

What are the types of visibility in Java?

Java provides four types of access modifiers or visibility specifiers i.e. default, public, private, and protected.


1 Answers

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.

enter image description here

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.

like image 190
S.D. Avatar answered Sep 18 '22 18:09

S.D.