views:

214

answers:

2

Please have a look at following code :

import java.util.ArrayList;
import java.util.List;

class Main{
     public static <T> List<T> modifiedList(final List<T> list){
         return new ArrayList<T>(){
            @Override
             public boolean add(T element){
                 super.add(element);
                 return list.add(element);
             }
         };
    }

     public static void main(String[] args) {
         List<String> originalList=new ArrayList<String>();
         List<String> duplicateList=modifiedList(originalList);
         originalList.add("1");
         originalList.add("2");
         originalList.add("3");
         System.out.println(originalList+" "+duplicateList);
         duplicateList.add("4");
         duplicateList.add("5");
         duplicateList.add("6");
         System.out.println(originalList+" "+duplicateList);
     }

In the above code, the instance of an anonymous inner class declared in the method modifiedList() is able to access the parameter passed to that method. AFAIK Java creates a separate bytecode file for inner classes.

Can anyone explain how these local variable bindings are handled by Java at the bytecode level? I mean, how exactly does Java keep track of the reference to the object passed as a parameter to that method?

Any help would be greatly appreciated!

[Sorry for my poor English! If you understand my question, please edit this post and remove the grammatical errors. Thanks!]

+8  A: 

Essentially the code is rewritten by the complier as (note I didn't try to compile it..., might have errors):

class Main$1<T>
    extends ArrayList<T>
{
    private final List<T> list;

    Main$1(final List<T> a)
    {
        list = a;
    }

    @Override
    public boolean add(T element)
    {
        super.add(element);
        return list.add(element);
    }
}

and

class Main{
     public static <T> List<T> modifiedList(final List<T> list)
     {
         return new Main$1<T>(list);
     }

     public static void main(String[] args) 
     {
         List<String> originalList=new ArrayList<String>();
         List<String> duplicateList=modifiedList(originalList);
         originalList.add("1");
         originalList.add("2");
         originalList.add("3");
         System.out.println(originalList+" "+duplicateList);
         duplicateList.add("4");
         duplicateList.add("5");
         duplicateList.add("6");
         System.out.println(originalList+" "+duplicateList);
     }
TofuBeer
Thanks a lot TofuBeer! I got my doubt cleared! :)
missingfaktor
That's why the compiler needs it declared final. For assuring that the value never changes, so the method inside the inner class can access the copied-never-changed value and know that's the correct semantics. If it were not final it shouldn't know if the value changed between inner object creation and inner object method invocation.
helios
+4  A: 
import java.util.ArrayList;
import java.util.List;

class Main{
    public static <T> List<T> modifiedList(final List<T> list){
         return new ArrayList<T>(){

             private List<T> originalList=list;

             @Override
             public boolean add(T element){
                 super.add(element);
                 return originalList.add(element);
             }
         };
     }

     public static void main(String[] args) {
         List<String> originalList=new ArrayList<String>();
         List<String> duplicateList=modifiedList(originalList);
         originalList.add("1");
         originalList.add("2");
         originalList.add("3");
         System.out.println(originalList+" "+duplicateList);
         duplicateList.add("4");
         duplicateList.add("5");
         duplicateList.add("6");
         System.out.println(originalList+" "+duplicateList);       
     }
 }

Java allows such a strange thing just in order to make things easier for programmers. Both the codes are semantically same and boil down to the identical bytecode.

Nikit Batale