简体   繁体   English

内部类非最终变量java

[英]inner class non-final variable java

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. 我需要更改内部类中的变量,并且我得到了臭名昭着的“不能引用在不同方法中定义的内部类中的非final变量”错误。

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. 另外,我真的很讨厌用temp这个词来命名我的班级。 Is there an actual programming term for what I did so that I make a more descriptive name for my class? 我是否有一个实际的编程术语,以便为我的课程创建一个更具描述性的名称?

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). 不需要任何黑客(如1个案例的数组)。

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. 1个成语的数组也会起作用,而且更简洁,但坦率地说,它看起来很难看。 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. 如果涉及多个线程,则还必须使用适当的同步。

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. 基本上这个想法是创建一个“包装器”,它包装了几乎任何Object类型。 Since final in Java stands for "no reassignment" and not "constant", this trick pretty much works out fine. 因为Java中的final代表“没有重新分配”而不是“常量”,所以这个技巧几乎可以解决。 But as mentioned in the original post, make sure you tread with caution when using it in a multi-threaded environment. 但正如原帖中所述,在多线程环境中使用它时,请务必小心谨慎。

I would keep a reference to your on click listener in the outer class, and make the int a member variable in your listener. 我会在外部类中保留对on click侦听器的引用,并使int成为侦听器中的成员变量。 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. 简单地说,如果内部类需要更改它,那么使它成为内部类中的变量。

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. 因为你似乎设置了多个东西(来自注释),所以在主类中创建一个方法, button1WasClicked() ,(一个更好的名字可能是doUpdate,doSave等 - 与按钮的作用相关的东西),放置正确的代码在那里,并从内部类/侦听器调用它。 (If you are using Swing I'd make it an Action, YMMV) (如果你使用Swing我会把它变为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. 这样,如果稍后存在需要执行相同内容的菜单或意图或手势,则呼叫就在那里。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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