Variable visibility in Java
java
Solution
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.
Problem
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(); } } ```