Java:在封闭范围内定义的局部变量 mi 必须是最终的或有效的最终

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33799800/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 15:02:54  来源:igfitidea点击:

Java: Local variable mi defined in an enclosing scope must be final or effectively final

java

提问by mallorn

I get the error, as in subject, and I kindly ask you how to repair it... ERROR is in menuItem-loop, where I try to set the textArea foreground colour to one picked from menuItem: (colors[mi])

我收到错误,如主题,我恳请您如何修复它...错误在 menuItem 循环中,我尝试将 textArea 前景色设置为从 menuItem 中选取的颜色:(colors[mi])

    String[] colors = {
            "blue", 
            "yellow",
            "orange",
            "red", 
            "white", 
            "black", 
            "green", 
            };

JMenu mnForeground = new JMenu("Foreground");
            for (int mi=0; mi<colors.length; mi++){
                String pos = Character.toUpperCase(colors[mi].charAt(0)) + colors[mi].substring(1);
                JMenuItem Jmi =new JMenuItem(pos);
                Jmi.setIcon(new IconA(colors[mi]));

                Jmi.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        JMenuItem item = (JMenuItem) e.getSource();
                        IconA icon = (IconA) item.getIcon();
                        Color kolorIkony = getColour(colors[mi]); // ERROR HERE: (colors[mi])
                        textArea.setForeground(kolorIkony);
                    }
                });

                mnForeground.add(Jmi);
            }

public Color getColour(String colour){
  try {
      kolor = Color.decode(colour);
  } catch (Exception e) {
      kolor = null; 
  }
  try {
        final Field f = Color.class.getField(colour);
        kolor = (Color) f.get(null);
      } catch (Exception ce) {
        kolor = Color.black;
      }
return kolor;
}

采纳答案by Jordi Castilla

The error means you cannot use the local variable miinside an inner class.

该错误意味着您不能mi在内部类中使用局部变量



To use a variable inside an inner class you must declare it final. As long as miis the counter of the loop and finalvariables cannot be assigned, you must create a workaround to get mivalue in a finalvariable that can be accessed inside inner class:

要在内部类中使用变量,您必须声明它final。只要mi循环的计数器和final变量不能被赋值,你就必须创建一个变通方法来获取mi一个final可以在内部类中访问的变量中的值:

final Integer innerMi = new Integer(mi);

So your code will be like this:

所以你的代码会是这样的:

for (int mi=0; mi<colors.length; mi++){

    String pos = Character.toUpperCase(colors[mi].charAt(0)) + colors[mi].substring(1);
    JMenuItem Jmi =new JMenuItem(pos);
    Jmi.setIcon(new IconA(colors[mi]));

    // workaround:
    final Integer innerMi = new Integer(mi);

    Jmi.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JMenuItem item = (JMenuItem) e.getSource();
                IconA icon = (IconA) item.getIcon();
                // HERE YOU USE THE FINAL innerMi variable and no errors!!!
                Color kolorIkony = getColour(colors[innerMi]); 
                textArea.setForeground(kolorIkony);
            }
        });

        mnForeground.add(Jmi);
    }
}

回答by QuakeCore

Yes this is happening because you are accessing mivariable from within your anonymous inner class, what happens deep inside is that another copy of your variable is created and will be use inside the anonymous inner class, so for data consistency the compiler will try restrict you from changing the value of miso that's why its telling you to set it to final.

是的,这是因为您mi从匿名内部类中访问变量,内部发生的事情是创建了变量的另一个副本并将在匿名内部类中使用,因此为了数据一致性,编译器将尝试限制您更改的值,mi这就是为什么它告诉您将其设置为最终的原因。

回答by Paul K.

What you have here is a non-local variable(https://en.wikipedia.org/wiki/Non-local_variable), i.e. you access a local variable in a method an anonymous class.

您在这里拥有的是一个非局部变量https://en.wikipedia.org/wiki/Non-local_variable),即您在匿名类的方法中访问局部变量。

Local variables of the method are kept on the stack and lost as soon as the method ends, however even after the method ends, the local inner class object is still alive on the heap and will need to access this variable (here, when an action is performed).

方法的局部变量保存在栈上,方法一结束就丢失,但是即使在方法结束后,局部内部类对象仍然在堆上活着,需要访问这个变量(这里,当一个动作进行)。

I would suggest two workarounds : Either you make your own class that implements actionlistennerand takes as constructor argument, your variable and keeps it as an class attribute. Therefore you would only access this variable within the same object.

我建议两种解决方法:要么创建自己的类,该类实现actionlistenner并接受构造函数参数,变量并将其保留为类属性。因此,您只能在同一对象中访问此变量。

Or (and this is probably the best solution) just qualify a copy of the variable finalto access it in the inner scope as the error suggests to make it a constant:

或者(这可能是最好的解决方案)只是限定变量的副本final以在内部范围内访问它,因为错误建议使其成为常量:

This would suit your case since you are not modifying the value of the variable.

这将适合您的情况,因为您没有修改变量的值。

回答by Manas

As I can see the array is of String only.For each loop can be used to get individual element of the array and put them in local inner class for use.

正如我所看到的,数组仅是字符串。每个循环可用于获取数组的单个元素并将它们放入本地内部类中以供使用。

Below is the code snippet for it :

下面是它的代码片段:

     //WorkAround 
    for (String color : colors ){

String pos = Character.toUpperCase(color.charAt(0)) + color.substring(1);
JMenuItem Jmi =new JMenuItem(pos);
Jmi.setIcon(new IconA(color));

Jmi.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            JMenuItem item = (JMenuItem) e.getSource();
            IconA icon = (IconA) item.getIcon();
            // HERE YOU USE THE String color variable and no errors!!!
            Color kolorIkony = getColour(color); 
            textArea.setForeground(kolorIkony);
        }
    });

    mnForeground.add(Jmi);
}

}

}

回答by Code-Apprentice

One solution is to create a named class instead of using an anonymous class. Give that named class a constructor that takes whatever parameters you wish and assigns them to class fields:

一种解决方案是创建一个命名类而不是使用匿名类。为该命名类提供一个构造函数,该构造函数接受您希望的任何参数并将它们分配给类字段:

class MenuActionListener implements ActionListener {
    private Color kolorIkony;

    public MenuActionListener(Color kolorIkony) {
        this.kolorIkony = kolorIkony
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        JMenuItem item = (JMenuItem) e.getSource();
        IconA icon = (IconA) item.getIcon();
        // Use the class field here
        textArea.setForeground(kolorIkony);
    }
});

Now you can create an instance of this class as usual:

现在您可以像往常一样创建此类的实例:

Jmi.addActionListener(new MenuActionListener(getColor(colors[mi]));