/*九格子游戏。请编写多线程游戏,设计一个3*3的格子(每个格子对应一个按钮)。
 * 每个格子上对应一个线程,格子上文字只能是A、X或H,而且刚好只有一个格子上是H。
 * 其中,H表示人在该格子上,A表示当前的格子是安全的,X表示不安全。每个格子如果不是文字H,
 * 则每过一段时间就切换其上的文字A与X。只能单击H所在的格子的上下左右按钮。如果单击的格子当时的文字是A,
 * 则单击的格子的文字变成H,而H原来所在格子的文字变为A(然后进行A与X的文字切换)。如果单击的格子当时是
 * 文字X,则gameover,如果文字H在每个格子上都出现过,则Pass。*//*題目要求是每个按钮对应一个线程,我只用了一个线程,就当着和main方法是多线程吧。
 * 现在的问题是程序刚开始运行正常,过一段时间(可能需要3~4分钟)会抛出数组越界和空指针的异常,
 * 我想可能是对按钮的处理出现的问题,由于我刚学一个月,周围也没人交流,所以望各位大虾大牛不吝赐教啊,
 * 占用您宝贵的时间感到万分抱歉,THX*/import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedList;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;class J_NineGrid extends JFrame
{
static JButton [][] b = {{new JButton("1"), new JButton("2"), new JButton("3")}, 
 {new JButton("4"), new JButton("5"), new JButton("6")},
 {new JButton("7"), new JButton("8"), new JButton("9")}};

int [][] flag= new int[3][3];  
Container c = getContentPane();

public J_NineGrid()
{
super("NineGridGame");

c.setLayout(new FlowLayout());

int [] list  = {1, 0, 1, 0, 1, 0, 1, 0, 2};
int [] rList = getList(list);         //  随机序列,用于初始化面板
String bText;

for (int i=0; i<3; i++)
for (int j=0; j<3; j++)
{
if (rList[i*3+j] == 1)
bText = "A";
else if (rList[i*3+j] == 0)
bText = "X";
else
bText = "H";

b[i][j].addActionListener(new ActionListener()  // 响应按钮事件
{
int cx , cy; // 当前按下按钮的坐标
int bx , by; // H按钮的坐标
boolean tag;

public void actionPerformed(ActionEvent e) 
{
JButton cButton = (JButton)e.getSource();
cx = Integer.parseInt(cButton.getName())/3;
cy = Integer.parseInt(cButton.getName())%3;

for (int i=0; i<3; i++)
for (int j=0; j<3; j++)
{
if (b[i][j].getText() == "H")
{
bx = i;
by = j;
flag[i][j] = 1;
break;
}
}

if (cButton.getText() != "H")
{
if (Math.abs(bx-cx)+Math.abs(by-cy) == 1)  // 判断是否是H按钮的上下左右按钮
{
if (cButton.getText() == "X")
System.out.println("Fail");
else if (cButton.getText() == "A")
{
cButton.setText("H");
b[bx][by].setText("A");
flag[cx][cy] = 1;
}
}
}

tag = true;
for (int i=0; i<3; i++)
for (int j=0; j<3; j++)
{
if (flag[i][j] == 0)
tag = false;
}
if (tag)
System.out.println("Pass(@_@)");
}
});

b[i][j].setText(bText);       // set button text
b[i][j].setName(""+(i*3+j));  // set button name
c.add(b[i][j]);
}
}

public void ChangeName()
{
String bText = "";
for (int i=0; i<3; i++)
for (int j=0; j<3; j++)
{
if(b[i][j].getText() == "A")
{
bText = "X";
}
else if(b[i][j].getText() == "X")
{
bText = "A";
}
else if(b[i][j].getText() == "H")
{
bText = "H";
}

b[i][j].setText(bText);         // set button text
c.add(b[i][j]);
}
}

public  int[] getList(int[] list)       // 产生随机序列
{
int count = list.length;
int [] resultList = new int[count];
LinkedList<Integer> temp = new LinkedList<Integer>();
for (int i=0; i<count; i++)
{
temp.add((Integer)list[i]);
}

Random rand = new Random();
for (int i=0; i<count; i++)
{
int num = rand.nextInt(count - i);
resultList[i] = (Integer)temp.get(num);
temp.remove(num);
}

return resultList;
}
}class T_ChangeName extends Thread
{
J_NineGrid game2;

public T_ChangeName(J_NineGrid game)
{
game2 = game;
}

public void run()
{
System.out.println("Begin");
for ( ; true; )
{
game2.ChangeName();
try 
{
Thread.sleep(2000);

catch (InterruptedException e) 
{
e.printStackTrace();
}
}
}
}public class J_NineGridGame 
{
public static void main(String args[])
{
J_NineGrid game = new J_NineGrid();
game.setLocationRelativeTo(null);
game.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.setSize(150, 150);
game.setVisible(true);

T_ChangeName thread = new T_ChangeName(game);
thread.start();
}
}
---------------------------------------------------
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: No such child: 8
at java.awt.Container.getComponent(Container.java:294)
at javax.swing.JComponent.rectangleIsObscured(JComponent.java:4339)
at javax.swing.JComponent.paint(JComponent.java:1027)
at javax.swing.JComponent.paintToOffscreen(JComponent.java:5124)
at javax.swing.BufferStrategyPaintManager.paint(BufferStrategyPaintManager.java:278)
at javax.swing.RepaintManager.paint(RepaintManager.java:1224)
at javax.swing.JComponent._paintImmediately(JComponent.java:5072)
at javax.swing.JComponent.paintImmediately(JComponent.java:4882)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:785)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:713)
at javax.swing.RepaintManager.seqPaintDirtyRegions(RepaintManager.java:693)
at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(SystemEventQueueUtilities.java:125)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:641)
at java.awt.EventQueue.access$000(EventQueue.java:84)
at java.awt.EventQueue$1.run(EventQueue.java:602)
at java.awt.EventQueue$1.run(EventQueue.java:600)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:611)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

解决方案 »

  1.   

    ArrayIndexOutOfBoundsException
    已经比较明显了
    自己好好检查下哪里越界了
    这么长的代码看不下去了 呵呵
    楼主自己找吧
      

  2.   

    java.lang.ArrayIndexOutOfBoundsException: No such child: 8 
    数组下标越界,也就是操作超出了数组的长度了
      

  3.   

    数组越界了,debug一步步往下走就能定位问题了。
      

  4.   

    程序差不多执行3分钟才跳出异常,那是个无限循环,每两秒执行一次,我要debug多久啊,我已经按了5分钟了,还没调出来啊
      

  5.   

    问题已经解决啦
    原来我不知道怎么刷新界面,改变了button的文本后没变化,我就又加一次button到frame,最后导致存放button 的容器满了,就越界了,不知道情况是不是这样,如果哪位有空的话,可以再帮我看看呀,下面是修改后的game。
    ths!
    package Exercise;
    /*九格子游戏。请编写多线程游戏,设计一个3*3的格子(每个格子对应一个按钮)。
     * 每个格子上对应一个线程,格子上文字只能是A、X或H,而且刚好只有一个格子上是H。
     * 其中,H表示人在该格子上,A表示当前的格子是安全的,X表示不安全。每个格子如果不是文字H,
     * 则每过一段时间就切换其上的文字A与X。只能单击H所在的格子的上下左右按钮。如果单击的格子当时的文字是A,
     * 则单击的格子的文字变成H,而H原来所在格子的文字变为A(然后进行A与X的文字切换)。如果单击的格子当时是
     * 文字X,则gameover,如果文字H在每个格子上都出现过,则Pass。*/import java.awt.Container;
    import java.awt.FlowLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.LinkedList;
    import java.util.Random;
    import javax.swing.JButton;
    import javax.swing.JFrame;class J_NineGrid extends JFrame
    {
    static JButton [][] b = new JButton[3][3];
    int [][] flag= new int[3][3];  

    public J_NineGrid()
    {
    super("NineGridGame");
    Container c = getContentPane();
    c.setLayout(new FlowLayout());

    int [] list  = {1, 0, 1, 0, 1, 0, 1, 0, 2};
    int [] rList = getList(list);                     //  随机序列,用于初始化面板 String bText;

    for (int i=0; i<3; i++)
    for (int j=0; j<3; j++)
    {
    if (rList[i*3+j] == 1)
    bText = "A";
    else if (rList[i*3+j] == 0)
    bText = "X";
    else
    bText = "H";

    b[i][j] = new JButton(bText);
    b[i][j].setName(""+(i*3+j));  

    b[i][j].addActionListener(new ActionListener()  // 响应按钮事件
    {
    int cx , cy; // 当前按下按钮的坐标
    int bx , by; // H按钮的坐标
    boolean tag;

    public void actionPerformed(ActionEvent e) 
    {
    JButton cButton = (JButton)e.getSource();
    cx = Integer.parseInt(cButton.getName())/3;
    cy = Integer.parseInt(cButton.getName())%3;

    for (int i=0; i<3; i++)
    for (int j=0; j<3; j++)
    {
    if (b[i][j].getText() == "H")
    {
    bx = i;
    by = j;
    flag[i][j] = 1;
    break;
    }
    }

    if (cButton.getText() != "H")
    {
    if (Math.abs(bx-cx)+Math.abs(by-cy) == 1)  // 判断是否是H按钮的上下左右按钮
    {
    if (cButton.getText() == "X")
    System.out.println("Fail");
    else if (cButton.getText() == "A")
    {
    cButton.setText("H");
    b[bx][by].setText("A");
    flag[cx][cy] = 1;
    }
    }
    }

    tag = true;
    for (int i=0; i<3; i++)
    for (int j=0; j<3; j++)
    {
    if (flag[i][j] == 0)
    tag = false;
    }
    if (tag)
    System.out.println("Pass(@_@)");
    }
    });

    c.add(b[i][j]);
    }
    }

    public void ChangeName(int bName)
    {
    String bText = "";
    int bx, by;
    bx = bName/3;
    by = bName%3;

    if(b[bx][by].getText() == "A")
    {
    bText = "X";
    }
    else if(b[bx][by].getText() == "X")
    {
    bText = "A";
    }
    else if(b[bx][by].getText() == "H")
    {
    bText = "H";
    }

    b[bx][by].setText(bText);           // 改变按钮文本

    }

    public  int[] getList(int[] list)       // 产生随机序列
    {
    int count = list.length;
    int [] resultList = new int[count];
    LinkedList<Integer> temp = new LinkedList<Integer>();
    for (int i=0; i<count; i++)
    {
    temp.add((Integer)list[i]);
    }

    Random rand = new Random();
    for (int i=0; i<count; i++)
    {
    int num = rand.nextInt(count - i);
    resultList[i] = (Integer)temp.get(num);
    temp.remove(num);
    }

    return resultList;
    }
    }class T_ChangeName extends Thread
    {
    J_NineGrid game2;
    int T_bName;

    public T_ChangeName(J_NineGrid game, int bName)
    {
    game2 = game;
    T_bName = bName;
    }

    public void run()
    {
    System.out.println("Button " + (T_bName+1) +" begin to work");

    for ( ; true; )
    {
    game2.ChangeName(T_bName);
    game2.repaint();             // 刷新界面
    try 
    {
    Thread.sleep((int)(Math.random()*6000));

    catch (InterruptedException e) 
    {
    e.printStackTrace();
    }
    }
    }
    }public class J_NineGridGame 
    {
    public static void main(String args[])
    {
    J_NineGrid game = new J_NineGrid();
    game.setLocationRelativeTo(null);
    game.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    game.setSize(150, 150);
    game.setVisible(true);

    T_ChangeName [] thread = new T_ChangeName[9];

    for (int i=0; i<9; i++)
    {
    thread[i] = new T_ChangeName(game, i);
    thread[i].start();
    }

    }
    }
      

  6.   

    错误的地方有好几处,比如:
     // ---------------------------------------------------------------------------------------------
        public int[] getList(int[] list) // 产生随机序列
        {
    int count = list.length;
    int[] resultList = new int[count];
    LinkedList<Integer> temp = new LinkedList<Integer>(); for (int i = 0; i < count; i++) {
        temp.add((Integer) list[i]);
    } // Random rand = new Random();
    // for (int i = 0; i < count; i++) {
    // int num = rand.nextInt(count - i); // resultList[i] = (Integer)
    // temp.get(num);//此时的temp长度可能变化,可能不变化,count-i是始终在变的,
    // temp.remove(num); //remove后 此时的temp长度可能变化,可能不变化
    // } Collections.shuffle(temp);// 打乱它
    for (int i = 0; i < count; i++) {
        list[i] = temp.get(i);// 复制到resultList;
    }
    return resultList;
        }
        // ------------------------------------------------------------------------------------------
    //我看上面的程序晕晕的,然后就没耐心了,干脆进行大幅度修改,修改后的程序如下:import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    import java.util.*;public class TestNineGridGame {
        public static void main(String[] args) {
    new GameFrame();
        }
    }class GameFrame extends JFrame {
        private JPanel gamePane = null;;    public GameFrame() {
    super("NineGridGame");
    // System.out.println("hi");
    launch();
        }    public void launch() {
    setTitle("controlPane");
    // setLayout(new FlowLayout());
    gamePane = new GamePanel(this);
    add(gamePane);
    setPreferredSize(new Dimension(150, 140));
    pack();
    setVisible(true);
    this.setLocationRelativeTo(null);
    this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        }
    }// ///////////////////////////////////////////////////////////////////////////////////////
    class GamePanel extends JPanel implements ActionListener {
        JFrame drawFrame;    enum Flag {
    A, X, H
        };    Flag flag;    private static final int BUTTON_ROW_SIZE = 3;
        private static final int BUTTON_COL_SIZE = 3;
        private static final int TIME_INTERVAL = 3000;// 3秒钟间隔
        private JButton[][] buttons = null;;// 面板上有9个JButton
        private String[][] texts = null;// 存放按钮对应的文本;
        private Set<JButton> passButtons = null; // 产生一个H在数组中的任意位置,然后其他位置随机填充"A","X";
        public GamePanel() {
    Launch();
        }    public GamePanel(JFrame drawFrame) {// 重载构造方法,接收传来的Frame
    this.drawFrame = drawFrame; ;
    Launch();
        }    void Launch() {
    setLayout(new FlowLayout());
    passButtons = new HashSet<JButton>();// 存放显示过“H”的按钮,
    texts = generateAXH();// 产生一个H在数组中的任意位置,然后其他位置随机填充"A","X";
    buttons = new JButton[GamePanel.BUTTON_ROW_SIZE][GamePanel.BUTTON_COL_SIZE];
    for (int i = 0; i < BUTTON_ROW_SIZE; i++) {// 面板上有9个JButton
        for (int j = 0; j < BUTTON_COL_SIZE; j++) {
    buttons[i][j] = new JButton(texts[i][j]);// 以随机产生的text初始化按钮
    add(buttons[i][j]);// 按钮添加到面板上
    buttons[i][j].addActionListener(this);// 每个按钮添加监听器,相当于每个按钮都有一个线程在监听鼠标
        }
    }
    new Thread(new PaintThread()).start();
        }    public String[][] generateAXH() {// 产生一个H在数组中的任意位置,然后其他位置随机填充"A","X";
    String texts[][] = new String[BUTTON_ROW_SIZE][BUTTON_COL_SIZE];
    int randomRow = (int) (Math.random() * BUTTON_ROW_SIZE);
    int randomCol = (int) (Math.random() * BUTTON_COL_SIZE);
    texts[randomRow][randomCol] = "H";
    for (int i = 0; i < BUTTON_ROW_SIZE; i++) {
        for (int j = 0; j < BUTTON_COL_SIZE; j++)
    if (texts[i][j] == null) {
        texts[i][j] = Math.random() < 0.5 ? "A" : "X";
    }
    }
    return texts;
        }    public void paintComponent(Graphics g) {// 重写paintComponent方法,
    super.paintComponent(g);
    for (int i = 0; i < GamePanel.BUTTON_ROW_SIZE; i++)
        for (int j = 0; j < GamePanel.BUTTON_COL_SIZE; j++) {
    if (buttons[i][j].getText().equals("A"))
        buttons[i][j].setText("X");
    else if (buttons[i][j].getText().equals("X")) {
        buttons[i][j].setText("A");
    }
        }
        }    public void actionPerformed(ActionEvent e) {// 实现每个按钮监听器的方法
    JButton jb = (JButton) e.getSource();
    if (jb.getText().equals("X")) {
        prompt("gameOver");
        System.exit(0);
    } int beforeRowOfH = 0;// 记录之前H的位置
    int beforeColOfH = 0;// 记录之前H的位置
    int nowRowOfH = 0;// 记录现在H的位置
    int nowColOfH = 0;// 记录现在H的位置 for (int i = 0; i < BUTTON_ROW_SIZE; i++)
        for (int j = 0; j < GamePanel.BUTTON_COL_SIZE; j++) {
    if (buttons[i][j].getText().equals("H")) {
        beforeRowOfH = i;
        beforeColOfH = j;
    }
    if (buttons[i][j] == jb) {
        nowRowOfH = i;
        nowColOfH = j;
    }
        } //行数相等列数差1 或者列数相等行数差1
    if ((nowRowOfH == beforeRowOfH && (nowColOfH == beforeColOfH + 1 | nowColOfH == beforeColOfH - 1))|
    (nowColOfH == beforeColOfH && (nowRowOfH == beforeRowOfH + 1 | nowRowOfH == beforeRowOfH - 1))) {
        if (jb.getText().equals("A")) {
    jb.setText("H");
    passButtons.add(buttons[nowRowOfH][nowColOfH]);// 将显示过“H”的按钮放入set
    if (passButtons.size() >= BUTTON_ROW_SIZE * BUTTON_COL_SIZE)
        prompt("pass");// 判断是否通过了
    buttons[beforeRowOfH][beforeColOfH].setText("A");
        }
    } else {// 非法点击按钮
        prompt("只能单击H所在的格子的上下左右按钮");
    }
        }
        
            public void prompt(String promptMessage) {
    JOptionPane.showConfirmDialog(null, promptMessage, "友情提示",
    JOptionPane.WARNING_MESSAGE);
        }    private class PaintThread implements Runnable {// JPanel重画的线程
    public void run() {
        while (true) {
    repaint();
    // updateUI();
    try {
        Thread.sleep(GamePanel.TIME_INTERVAL);// /过一段时间,就重画面板
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
        }
    }
        }
    }
      

  7.   

    謝謝樓上啊,等我看完了就結貼还有个小问题要问下:
    Java程序的排版问题,和C++有区别吗,那个花括号我以前都喜欢另起一行,那样一目了然,看起来还整洁一些,但我看很多java程序都不是这种排版,我该改过来吗?
      

  8.   

    代码排版只要自己写着习惯,别人看着顺眼就行,没必要非要和别人一样。
    (当然,如果公司有代码规范的话还是要按规范做)。Ecipse的代码排版设置项是
    Java->Code Style->Formatter
    可以设置成自己想要的格式。
      

  9.   

       
        看代码太乱了,一个注释都没有!
        没看错的话,这只是一个单线程的吧。。
        即然不是多线程,还要用什么Thread。。不用也可以实现吧。。
      

  10.   

    for ( ; true; )这是死循环么,不行同步看看