简体   繁体   中英

Final Local Variable may not have been initialized in anonymous inner class

Here is my code:

final Foo myFoo = new Foo(new Inner() {
    @Override
    callback(){
         myFoo.bar();
    }
});

(With actual function names)

final MyArrayAdapter aa = new MyArrayAdapter(new View.OnClickListener() {
    @Override
    onClick(){
         aa.notifyDataSetChanged();
    }
});

Java is giving me an error about how myFoo might not have been initialized. Is there any way to fix this? I can potentially set the callback to null when I construct the object and then change it afterwards, but I'd hope for there to be a cleaner way. Any ideas? (Also that wouldn't work if Foo wasn't written by me and didn't expose an interface to change the callback later)

In case anyone is curious, in my specific scenario, Foo is an ArrayAdapter, and the bar is notifyDataSetChanged(). What is displayed by the adapter depends on the values of the items in the array, and those values change when they are clicked on. The callback is the clickListener.

Short answer is that you definitely can't do that in Java, but the compiler already told you that. You're trying to create two objects at once with references to each other, it's a chicken and egg problem. Bottom line, you have to create ONE of them first.

A suggestion is a two step creation:

....
final MyArrayAdapter aa = new MyArrayAdapter();
aa.initializeButtonClickListener();
....

and then add the 'initialize' method to the adapter.

public void initializeButtonClickListener(){
    this.button.setOnClickListener(new View.OnClickListener() {
        @Override
        onClick(){
             notifyDataSetChanged();
        }
    });
}

Because that construction is somewhat complicated (ie, more complicated than simply calling a constructor), I'd recommend then pulling those two lines in to a MyArrayAdapter factory method, and making the constructor private.

This will work in general and without access the Inner definition, but you do need to create a helper class:

class CallbackHelper {
    private Foo foo;
    public void setFoo( Foo f ){ foo = f; }
    public Foo getFoo(){ return foo; }
}

And then use it like this:

final CallbackHelper cbh = new CallbackHelper();
Foo myFoo = new Foo(new Inner() {
    @Override
    callback(){
         cbh.getFoo().bar();
    }
});
cbh.setFoo( myFoo );

You could declare a method callBarOnMyFoo in the containing class and call it from your callback:

void callBarOnMyFoo() {
    myFoo.bar();
}

Then your callback would need to call callBarOnMyFoo , which is an instance method of the outer class, which the Inner code should have a reference to (I forget the syntax for it offhand).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM