2014-12-19 103 views
7

我有一个局部变量访问内部类的问题需要声明为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

[变量可能在内部类中被访问。需要被宣布为最终](http://stackoverflow.com/questions/14425826/variable-is-accessed-with-inner-class-needs-to-be-declared-final) – Suragch 2016-12-05 05:00:51

回答

20

匿名内部类可以访问本地变量通过幕后的把戏。局部变量被实现为内部类的隐藏成员变量。他们被分配了局部变量的副本。为了防止复制值错误,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但从来没有改变过一次初始化。

+0

真正的问题是为什么他们使用复印件? – Ced 2016-06-04 18:29:48

4

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

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]); 
    } 
} 
相关问题