user334856
user334856

Reputation:

How can an java event listener defined as an anonymous inner class use a variable from an enclosing class?

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.

Upvotes: 2

Views: 1379

Answers (3)

John Watts
John Watts

Reputation: 8875

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();
    }
}

Upvotes: 2

willcodejavaforfood
willcodejavaforfood

Reputation: 44073

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

Upvotes: 1

SirDarius
SirDarius

Reputation: 42899

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

Upvotes: 1

Related Questions