8

I am passing an interface as anonymous implementation to a different object like this:

public interface Interface {
    public int convert (int a);
}



public static void main(String[] args) throws IOException, InterruptedException {

    final int[] array = {1,6,3,5,7,8,4,0,3};
    Interface inter = new Interface() {         
        public int convert(int a) {
            int result = a;             
            for (int i = 0; i < array.length; i++) {
                a=a+array[i];
            }               
            return a;
        }
    };

    SomeObject ty = new SomeObject ();
    ty.Test(7, inter);
}

public class SomeObject {   

    public void Test(int number, Interface inter) {             
        System.out.println(inter.convert(number));
    }
}

My question is: how does it work? How does SomeObject know about the array which is not passed directly to the object (array is not a member of the anonymous class).

Update
(sorry for late update)

what about member vars or methods methods that are used in the anonymous class? they are not final

Interface inter = new Interface() {         
    public int convert(int a) {
        int result = a + someMemberVar;             
        for (int i = 0; i < array.length; i++) {
            a=a+array[i];
        }               
        return a;
    }
};
Mukit09
  • 2,956
  • 3
  • 24
  • 44
omrid
  • 497
  • 3
  • 10
  • 20

6 Answers6

2

My question how does it work? How SomeObject knows about the array which is not passed directly to the object (array is not a member of the anonymous class).

  • Answer: It doesn't; unless you declare array as final.
  • Reasoning: It works (if array is final) because since it's final, it can be treated like a constant, since the anonymous function knows that the array cannot be changed.

what about member vars or methods methods that are used in the anonymous class? they are not final

  • Answer: Instance variables and methods (as well as static variables and methods) are in scope anyway, when the anonymous class is created.
Jon Newmuis
  • 25,722
  • 2
  • 45
  • 57
  • so the whole array in it's current state passed to SomeObject as constant? – omrid Dec 20 '11 at 15:35
  • 1
    Only a reference to the array object is passed to the anonymous class. If the declaring method changed the array *elements*, the anonymous class would see that. – Christian Semrau Dec 20 '11 at 15:47
  • @Jonathan Could you elaborate on visibility? It doesnt just work because its final. -1 (will remove once visibility is addressed) – Stefan Dec 20 '11 at 16:29
2

Since, the method-local variable is declared directly inside a method block it is visible only within the method, starting from the next statement after it's declaration. And by method-local I mean the variable that is declared inside the method but outside any other blocks (e.g. while { /* not here */ }) that might appear within that method.

And if you see, your anonymous class is also defined as a local class within the same method after the array's declaration. That's why it is visible to the class.

The reason that you need to make array final to be able to use it inside the anonymous class is that local variables live only till the method lives but the object of the local class might live longer (even after the method is done).

Bhesh Gurung
  • 50,430
  • 22
  • 93
  • 142
1

This is part of scoping and visibility rules for Java. In your current example its called a Closure. Basically everything that is defined in a block is visible inside that block. For an example this is valid Java code(anywhere in a method):

{
    final int i = 5;
    // do somthing with i
}
// cant refernce i here
{
    final int i = 6;
    // do somthing with i
}
// cant refernce i here

Since you define a new class inside the block(i wouldnt work if you just instanciated it) it sees everything declared in the same block. The only limit Java puts on it, is that you cant change the value after the first assignment, to avoid issues when the reference 'escapes' its block(multi threaded, lives longer than the declaring block etc.). If you declare the parameters of the method final you could use them aswell, because they are defined within the same block.

So if you changed your code to this

      {
          final int[] array = {1,6,3,5,7,8,4,0,3};
      }
      Object inter = new Object() 
      {           
          public void test() 
          {
              System.out.println(array);
          }
      };

It would not work(try it).

Stefan
  • 838
  • 3
  • 13
  • 28
0

You are passing object Interface that has access to the array into SomeObject method.

So SomeObject is using the same object Interface that you passed on main.

Since Interface has access to the array, it is possible to use it.

It is not SomeObject that is using the array. It is Interface object.

pringi
  • 3,987
  • 5
  • 35
  • 45
0

Java keeps a reference to all (final) objects of the enclosing class used in the inner class. If you want to know how this trick is maid, add the following line to Test method:

System.out.println(inter.getClass().getDeclaredConstructors()[0].getParameterTypes()[0].getCanonicalName()

And your output will be "int[]"

So, the compiler simple creates a constructor for the inner class and pass it the fields it needs

Pablo Grisafi
  • 5,039
  • 1
  • 19
  • 29
0

Compiler treats final variable as a constant, and substitues the value of corresponding variable into anonymous class at compile time itself. Following thread provides excellent details:
Cannot refer to a non-final variable inside an inner class defined in a different method

Community
  • 1
  • 1
Sumit
  • 706
  • 1
  • 8
  • 16