I got a problem of local variable access to inner class need to be declared final. It is from method createGrids() -> "squares[i][j] = 0;
" that i is a local variable that need to be declared final. I don't know why and I have added final in fields but it is not working as well.
import java.util.ArrayList;
import java.util.Random;
//omitted
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<Integer> list = new ArrayList<Integer>();
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);
}
}
Anonymous inner classes have access to local variables through a trick behind the scenes. Local variable are implemented as hidden member variables of the inner class. They are assigned copies of the local variable. To prevent the copy value from being wrong, the Java compiler enforces that these local variables must be
final
so they aren't changed, so the copy stays correct.The fields of the enclosing class don't need to be
final
; the local variables used must befinal
. You must make all local variables used in your anonymous inner classfinal
. You can do this by declaringfinal
variables to be initialized to youri
andj
values, and use them in your anonymous inner class.Note that in Java 8, this would not be necessary, because the Java 8 compiler can detect if the local variables used in anonymous inner classes are "effectively final", that is, not
final
but never changed once initialized.What is happening is that you are creating 81 ActionListener classes, each one with its own
actionPerformed
method. But when that method is executed, the class doesn't know what the value ofi
andj
is anymore, since it left them far behind.Java prevents this from happening, hence the compiler error. It requires any referenced local variables to be final so that it can pass them to the created classes.
The simplest way to solve this is to create a pair of
final
variables inside your loops: