我遇到了一个局部变量访问内部类的问题,需要声明final。它来自方法createGrids() - > " squares[i][j] = 0;
"我是一个需要被声明为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<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);
}
}
答案 0 :(得分:23)
匿名内部类可以通过幕后技巧访问局部变量。局部变量实现为内部类的隐藏成员变量。它们被分配了局部变量的副本。为了防止复制值出错,Java编译器强制要求这些局部变量必须为final
,这样它们才不会被更改,因此副本保持正确。
封闭类的字段不需要final
;使用的局部变量必须是final
。您必须在匿名内部类final
中使用所有局部变量。您可以将final
变量声明为初始化为i
和j
值,并在匿名内部类中使用它们。
// 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编译器可以检测匿名内部类中使用的局部变量是否有效#&#34;,即不是{{1}但是一旦初始化就永远不会改变。
答案 1 :(得分:4)
发生的事情是您正在创建81个ActionListener类,每个类都有自己的actionPerformed
方法。但是当执行该方法时,该类不再知道i
和j
的值是什么,因为它远远落后于它。
Java防止这种情况发生,因此编译错误。它要求任何引用的局部变量都是最终的,以便它可以将它们传递给创建的类。
解决此问题的最简单方法是在循环中创建一对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]);
}
}