对内部类的局部变量访问需要声明为final

我遇到了一个局部变量访问内部类的问题,需要声明final。 它来自方法createGrids() – >“ squares[i][j] = 0; ”我是一个需要声明为final的局部变量。 我不知道为什么,我在字段中添加了final,但它不能正常工作。

 import java.util.ArrayList; import java.util.Random; 

//省略

 public class Minesweeper{ private JFrame frame; private int cols = 9; private int rows = 9; public static final int GRID_HEIGHT = 9; public static final int GRID_WIDTH = 9; final JButton[][] grids = new JButton[GRID_WIDTH][GRID_HEIGHT]; final int [][] squares = new int [GRID_WIDTH][GRID_HEIGHT]; private static int width = 500; private static int heigth = 400; private JPanel s; private JPanel n; private JPanel w; private int mines = 10; private int bomb = 1; private JLabel j1; private JPanel e; private JRadioButton moreGrid; ArrayList list = new ArrayList(); public Minesweeper() { mines=10; createGrids(); s = new JPanel(); n = new JPanel(); e = new JPanel(); w = new JPanel(); resetButton = new JButton("Rest"); resetButton.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ createGrids();} }); newGameButton = new JButton("New Game"); frame.add(n, BorderLayout.NORTH); frame.add(w, BorderLayout.WEST); frame.add(s, BorderLayout.SOUTH); s.add(resetButton); s.add(newGameButton); } public void game() { for(int i = 0; i < GRID_WIDTH; i++) { for(int j = 0; j < GRID_HEIGHT; j++) { squares[i][j] = 0; } } } public void setRandom() { Random r = new Random(); for(int x = 0; x < mines; x++){ int b = r.nextInt(9); int c = r.nextInt(9) ; squares[b][c] = bomb; } } public void createGrids(){ frame = new JFrame("Minesweeper"); createMenuBar(frame); frame.setTitle("Nicholas Minesweeper"); JPanel m = new JPanel(new GridLayout(9,9)); for(int i = 0; i < GRID_WIDTH; i++) { for(int j = 0; j < GRID_HEIGHT; j++) { grids[i][j] = new JButton(); grids[i][j].addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ if (squares[i][j] == 1) { System.out.println("BOmb"); } else { grids[i][j].setVisible(false); } } }); m.add(grids[i][j]); } } frame.add(m, BorderLayout.CENTER); frame.setResizable(false); frame.setSize(width, heigth); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); frame.setSize(350, 250); frame.setVisible(true); } } 

匿名内部类可以通过幕后技巧访问局部变量。 局部变量实现为内部类的隐藏成员变量。 它们被分配了局部变量的副本。 为防止复制值出错,Java编译器强制要求这些局部变量必须是final以便它们不会更改,因此副本保持正确。

封闭类的领域不需要是final ; 使用的局部变量必须是final 。 您必须在匿名内部类final使用所有局部变量。 您可以通过将final变量声明为初始化为ij值来实现,并在匿名内部类中使用它们。

 // Inside the for loops in the createGrids method grids[i][j] = new JButton(); // Declare x, y final final int x = i; final int y = j; grids[i][j].addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ // Use x, y instead of i, j inside. if (squares[x][y] == 1) { System.out.println("BOmb"); } else { grids[x][y].setVisible(false); } } }); 

请注意,在Java 8中,这不是必需的,因为Java 8编译器可以检测匿名内部类中使用的局部变量是否“有效最终”,即,不是final但在初始化后永远不会更改。

发生的事情是你正在创建81个ActionListener类,每个类都有自己的actionPerformed方法。 但是当执行该方法时,类不知道ij的值是什么,因为它远远落后于它们。

Java可以防止这种情况发生,因此编译错误。 它需要任何引用的局部变量为final,以便它可以将它们传递给创建的类。

解决此问题的最简单方法是在循环中创建一对final变量:

 for(int i = 0; i < GRID_WIDTH; i++) { for(int j = 0; j < GRID_HEIGHT; j++) { grids[i][j] = new JButton(); final int x = i; // <-- Add these final int y = j; grids[i][j].addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ if (squares[x][y] == 1) // <-- change from squares[i][j] { System.out.println("BOmb"); } else { grids[x][y].setVisible(false); // <-- change from grids[i][j] } } }); m.add(grids[i][j]); } }