2014-12-19 2 views
7

내부 클래스에 대한 로컬 변수 액세스 문제가있어 최종 선언해야합니다. 메소드 createGrids() -> "squares[i][j] = 0;"에서 i는 final로 선언해야하는 로컬 변수입니다. 나는 왜 그런지 모르겠다. 필드에서 결승전을 추가했지만 제대로 작동하지 않는다.내부 클래스에 대한 로컬 변수 액세스를 최종 선언해야합니다.

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

// 당신이 (81 개)의 ActionListener 클래스 자체 actionPerformed 방법 하나 하나를 만드는 것이 무엇 일어나고있는 것은

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-within-inner-class-needs-to-be-declared-final) – Suragch

답변

20

익명 내부 클래스가 무대 뒤에서 트릭을 통해 지역 변수에 액세스 할 수 있습니다. 지역 변수는 내부 클래스의 숨겨진 멤버 변수로 구현됩니다. 로컬 변수의 복사본이 할당됩니다. 복사 값이 잘못되지 않도록하기 위해 Java 컴파일러는 이러한 로컬 변수가 변경되지 않도록 final이어야하므로 복사본을 그대로 유지합니다.

둘러싸는 클래스의 필드는 final 일 필요는 없습니다. 사용 된 지역 변수는 final이어야합니다. 익명 내부 클래스에 사용 된 모든 로컬 변수를 final으로 만들어야합니다. final 변수를 ij 값으로 초기화하고 익명의 내부 클래스에서 사용하도록 선언하면됩니다. 익명의 내부 클래스에서 사용되는 지역 변수 "효과적으로 최종"경우 자바 (8) 컴파일러가 감지 할 수 있기 때문에 자바 8에,이, 필요하지 않을 것이라고

// 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); 
     } 
    } 
}); 

주, 즉,하지 final 그러나 결코 한 번으로 변경 초기화 됨.

+0

진짜 질문은 왜 그들이 사용합니까 사본? – Ced

4

를 생략. 그러나이 메소드가 실행될 때 클래스는 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]); 
    } 
}