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

mal*_*orn 18 java

我得到了错误,就像在主题中一样,我恳请你如何修复它... ERROR在menuItem-loop中,我尝试将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;
}
Run Code Online (Sandbox Code Playgroud)

Jor*_*lla 28

该错误意味着您无法mi在内部类中使用局部变量.


要在内部类中使用变量,必须声明它final.只要无法分配mi循环和final变量的计数器,就必须创建一个变通方法来获取可在内部类中访问mifinal变量中的值:

final Integer innerMi = new Integer(mi);
Run Code Online (Sandbox Code Playgroud)

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

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 您还可以使用声明为final的AtomicInteger.在每次循环迭代中,您只需要调用mi.incrementAndGet()而不是mi ++. (2认同)

Qua*_*ore 7

是的,这是因为你正在mi从你的匿名内部类中访问变量,内部发生的是你的变量的另一个副本被创建并将在匿名内部类中使用,所以为了数据一致性,编译器将尝试限制你改变它的价值,mi这就是它告诉你把它设置为最终的原因.


Pau*_* K. 6

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

方法的局部变量保留在堆栈中,并在方法结束后立即丢失,但是即使在方法结束后,局部内部类对象仍然存在于堆上,并且需要访问该变量(这里,当一个动作被执行)。

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

或者(这可能是最好的解决方案)只需限定变量的副本final即可在内部作用域中访问它,因为错误建议将其设为常量:

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