问题
I needed to change variables inside an inner class and I got the infamous "Cannot refer to a non-final variable inside an inner class defined in a different method" error.
void onStart(){
bt.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
int q = i;
}
});
}
I quickly made a class that held all of the things I wanted to change and made a final version of the class outside the inner class
class temp{
int q;
}
void onStart(){
final temp x = new temp();
bt.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
x.q = i;
}
});
}
This seems to be what I need and it works but I am wondering if this is how to correctly work around the problem. Also, I really hate using the word temp
to name my class. Is there an actual programming term for what I did so that I make a more descriptive name for my class?
回答1:
You can simply create an inner class instead of an anonymous one (like you are currently doing). Then you have a constructor and any other methods you want to set your members. No hackiness required (like the array of 1 case).
I find this cleaner if the class requires any exchange of data with its outer class, but admit it is a personal preference. The array of 1 idiom will work as well and is more terse, but frankly, it just looks fugly. I typically limit anonymous inner classes to those that just perform actions without trying to update data in the outer class.
For example:
private MyListener listener = new MyListener();
void onStart(){
bt.setOnClickListener(listener);
}
class MyListener implements OnClickListener
{
String name;
int value;
void setName(String newName)
{
name = newName;
}
void setValue(int newValue)
{
value = newValue;
}
public void onClick(View v)
{
// Use the data for some unknown purpose
}
}
If there are multiple threads involved, then appropriate synchronization will have to be used as well.
回答2:
I posted a similar answer in my other thread here. Basically the idea is to create a "wrapper" which wraps over pretty much any Object
type. Since final
in Java stands for "no reassignment" and not "constant", this trick pretty much works out fine. But as mentioned in the original post, make sure you tread with caution when using it in a multi-threaded environment.
回答3:
I would keep a reference to your on click listener in the outer class, and make the int a member variable in your listener. Just store the variable in the listener on click, then grab the variable in the outer class when you need it, rather than setting it at the point of the click.
To put it simply, if the inner class needs to change it, make it a variable in the inner class.
回答4:
Since you appear to be setting multiple things (from the comments), make a method in the main class, button1WasClicked()
, (a better name might be doUpdate, doSave etc. - something relevant to what the button does), put the proper code there, and call it from the inner class / listener. (If you are using Swing I'd make it an Action, YMMV)
That way if later on there is a menu or an intent or a gesture that needs to execute the same stuff, the call is there.
来源:https://stackoverflow.com/questions/11316954/inner-class-non-final-variable-java