views:

39

answers:

3

Here's the code:

protected Dialog onCreateDialog(int id) {
    Dialog dialog = null;
    if (id == DIALOG_SEARCH) {
        dialog = new Dialog(this);
        dialog.setContentView(R.layout.search_dialog_layout);
        dialog.setTitle("Search Dialog");
        Button button = (Button) dialog.findViewById(R.id.Button01);
        final Button button2 = (Button) dialog.findViewById(R.id.Button02);
        button2.setEnabled(false);
        button.setOnClickListener(new OnClickListener() {
            public void onClick(View arg0) {
                button2.setEnabled(true);
            }
        });
    }
    return dialog;
}

How does the anonymous inner class (the OnClickListener) have access to the button2 variable? Its onClick method is called at some random time in the future when button is clicked. In what context does this function run? How does it know about button2? I'm just confused about the scoping and context here.

+1  A: 

There's a pretty thorough explanation here: http://renaud.waldura.com/doc/java/final-keyword.shtml#vars

SirDarius
+1  A: 

Any anonymous class you create will retain a reference to the enclosing class which lets them access the variables in the outer class.

willcodejavaforfood
+1  A: 

Often, the best way to find out how the Java compiler does something is to compile the class and then run it through Jad (JAva Decompiler). In this case, it appears that javac just creates an extra variable on the anonymous inner class named "val$o" and initializes it in a static initializer. Seeing this transformation makes it clearer why Java requires that you make the variable final before using it in an anonymous inner class. Without the requirement, the two variables could end up with different values at runtime. Also, this is really no different than the mechanism Java uses to allow all inner classes (anonymous or named) access to their containing class. You can see that the inner class contains a reference to the containing class's this variable, named "this$0".

I compiled a simpler example:

public class Outer {

    public void outerMethod() {
        final Object o = "fromOuter";
        new Object() {
            public void innerMethod() {
                System.out.println(o);
            }
        }.innerMethod();
    }
}

and got this out the other end:

public class Outer {

    public Outer()
    {
    }

    public void outerMethod()
    {
        final Object o = "fromOuter";
        (new Object() {

            public void innerMethod()
            {
                System.out.println(o);
            }

            final Outer this$0;
            private final Object val$o;


            {
                this$0 = Outer.this;
                o = obj;
                super();
            }
        }).innerMethod();
    }
}
John Watts
Thanks! All answerers agreed, but I like this one because you showed me how I would figure this out on my own. One follow-up... where is this behaviour officially described?
Sancho