7

I am new to java and trying some accessing methods and i encountered something that i do not understand. The code below working fine, prints 9 and not giving any compilation errors. I think this code should give a compilation error and number should be inaccessible from the test method, since new Human() is an instance of a totally different class. Can anybody explain me what is happening here ?

public class Test{      
    public static void main(String[] args) {
        int number = 9;

        test("holla",new Human(){   
            @Override
            void test() {
                // TODO Auto-generated method stub
                System.out.println(number); // I think this line should not compile
            }               
        });    
    }

    private static void test(String a ,Human h){            
        h.test();           
    }    
} 

Human Class

public abstract class Human {       
    abstract void test();    
}
Assafs
  • 3,257
  • 4
  • 26
  • 39
rematnarab
  • 1,277
  • 4
  • 22
  • 42
  • What is `Human` and why do you think you couldn't access the variable `number` in a method where it was declared? – Tom Aug 22 '17 at 12:31

2 Answers2

12

You are correct before java 8.

In addition, a local class has access to local variables. However, a local class can only access local variables that are declared final. When a local class accesses a local variable or parameter of the enclosing block, it captures that variable or parameter.

Local variables should be final inorder to accessible inside anonymous classes.

Starting with Java 8, effectively final variables also allowed to access inside.

However, starting in Java SE 8, a local class can access local variables and parameters of the enclosing block that are final or effectively final. A variable or parameter whose value is never changed after it is initialized is effectively final.

try

int number = 9;
number=10;

now number is not at all effectively final and you get a compiler error saying "Local variable number defined in an enclosing scope must be final or effectively final".

You might want to read Difference between final and effectively final

Suresh Atta
  • 120,458
  • 37
  • 198
  • 307
7

This is perfectly valid (for java8 - prior to that, you would need thje final keyword when declaring number):

  • you create an anonymous inner class that extends Human and provides the required implementation of the test() method.
  • that method is using a variable from its enclosing "scope" - and the compiler is smart enough to detect that this variable is in fact a constant - as there no other subsequent assignments to it.

In order to "invalidate" your example: simply add an assignment

number = 42; 

within the main method - after defining that anonymous inner class. Or use some version of java that is older than java8.

Keep in mind that anonymous inner classes are closures, and that the JVM is copying the values that are required "inside" from the outside. But when the outside value changes - which value should be copied. See here for further reading.

GhostCat
  • 137,827
  • 25
  • 176
  • 248