五子棋的Java实现 详解

最近用Java写了一个有人机对战人人对战两种模式的五子棋小游戏,也算是有自己一定的心得,现在把它分享出来。代码我会放在最后面,先把五子棋的思路捋清楚

一、首先上界面图

五子棋的Java实现 详解_第1张图片
这是我五子棋的界面,比较简单,大家可以根据自己的想法随意DIY.

二、如何实现界面?

这个五子棋界面,由四个类实现,分别是:
JFrame(作为顶层容器类的JFrame用来添加其他的所有组件)
JPanel(在界面中用来分别添加棋盘界面和按钮界面)
JButton(在界面作为按键如“开始”“认输”“重新开始”按键)
JRadioButton(在界面中作为单选按钮如“人人对战”“人机对战”)

界面中有两个JPanel面板对象,一个在界面的左边用来绘制棋盘,一个在界面的右边用来放置按键。
给出界面实现代码

public class FiveChess extends JPanel{
    public Graphics g;                          //五子棋盘里面的Graphics属性用来画图
    public static void  main (String args[]){
        FiveChess fc=new FiveChess();           //实例化五子棋盘类得到五子棋盘对象fc
        fc.go();                                //五子棋盘对象fc调用go()
    }
    public void setG(Graphics g){               //五子棋盘类用来设置Graphics属性的方法
        this.g=g;
    }
    public void go(){
        /*
         * 创建一个窗体,设置窗体里的属性
         */
        JFrame frame=new JFrame();              //实例化一个窗体对象frame
        frame.setTitle("五子棋");                  //设置窗体的标题
        frame.setSize(800,500);                 //设置窗体的大小
        frame.setDefaultCloseOperation(3);
        /*
         * 添加两个面板 利用board布局 一个放中间 用来画五子棋的棋盘 一个放东边用来放置按钮
         */
        JPanel buttonpanel=new JPanel();                        //实例化一个面板对象buttonpanel
        buttonpanel.setPreferredSize(new Dimension(300,500));//设置buttonpanel大小 只有窗体对象能够用setSize()
        buttonpanel.setBackground(Color.white);             //设置buttonpanel对象的背景颜色
        /*
         * 添加按钮
         */
         //实例化三个按钮对象    
        JButton bstart=new JButton("开始");               
        JButton bquit=new JButton("认输");
        JButton bundo=new JButton("悔棋");

        //设置三个按钮对象的大小
        bstart.setPreferredSize(new Dimension(200,50));     
        bquit.setPreferredSize(new Dimension(200,50));
        bundo.setPreferredSize(new Dimension(200,50));
        //将这三个按钮对象添加到面板对象bp中去
        buttonpanel.add(bstart);                                    
        buttonpanel.add(bquit);
        buttonpanel.add(bundo);

        //实例化按钮组对象bg
        ButtonGroup bg=new ButtonGroup();               
        //实例化两个单选按钮对象
        JRadioButton bpvp=new JRadioButton("人人对战"); 
        JRadioButton bpvr=new JRadioButton("人机对战");
        //设置两个单选按钮对象的大小
        bpvp.setPreferredSize(new Dimension(200,50));   
        bpvr.setPreferredSize(new Dimension(200,50));
        //将这两个单选按钮对象设为透明背景
        bpvr.setOpaque(false);                          
        bpvp.setOpaque(false);
        bg.add(bpvp);                                   //将这两个单选按钮对象添加到按钮组对象bg中
        bg.add(bpvr);
        //将这两个单选按钮对象添加到面板对象buttonpanel中
        buttonpanel.add(bpvp);                                  
        buttonpanel.add(bpvr);  
        this.setBackground(Color.gray);                 //棋盘对象设置背景色
        /*
         * 窗体布局,将棋盘面板和按钮面板合理地布局在frame窗体对象上
         */
        BorderLayout bl=new BorderLayout();             //实例化一个布局对象     
        frame.setLayout(bl);                            //将窗体对象frame设置为BorderLayout
        frame.add(this,BorderLayout.CENTER);            //把棋盘对象放在窗体对象的中间
        frame.add(bp,BorderLayout.EAST);                //把按钮面板放在窗体对象的东边
        frame.setVisible(true);                         //窗体对象设置为可见
        //棋盘对象设置Graphics属性
        g=this.getGraphics();   
    }
}

以上这段代码并没有给出如何画出15*15的棋盘
因为棋盘是在左边板上画出来的我们可以利用左边面板的重绘paint()方法画15*15棋盘

   /*
     *画五子棋棋盘的方法
     */
    public void draw(Graphics ag){
        Graphics2D g=(Graphics2D)ag;
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);

        for(int i=0;i<15;i++){
            for(int j=0;j<15;j++){
                /*
                 * 首先把棋盘重新画一遍
                 */
                g.setColor(Color.black);
                g.drawLine(30,30+i*30,450,30+i*30); //画横线
                g.drawLine(30+i*30,30,30+i*30,450); //画竖线
            }
        }

重写paint()方法

    public void paint(Graphics g){
        super.paint(g);
        draw(g);
    }

有了以上这几段代码我们就能完全实现如图所示的界面了。

有了界面之后,棋子呢?

当我们做好界面之后理所应当地需要在棋盘面板上放置棋子。
Java是一门面向对象的语言,我们可以把棋子作为一个类。
在棋盘上每一个横竖线交叉的地方都应该有一个棋子,在相对应的地方没有下棋的时候,棋子是隐形的棋子状态flag为0,在相对应的位置下完棋之后棋子状态flag为1(白棋)或者2(黑棋)。

public class chess {
     public int X,Y;    // X,Y是棋子对应在棋盘上的坐标,我们之后就是利用棋子的坐标,在棋盘上画出它。
     public int flag;   //代表棋子的三种状态flag:0 没有落子 flag:1 白子 flag:2 黑子
     public int value;  //该棋子的权值 
     public chess(){
         X=0;
         Y=0;
         flag=0;
         value=0;
     }
     public chess(int x,int y){
         X=x;
         Y=y;
         flag=0;
         value=0;
     }
}

我们可以定义一个15*15的二维数组 数组下标代表棋子在棋盘的相应位置,而棋子的X Y属性代表棋子在棋盘上的坐标值。最左上角的棋子坐标为X:30,Y:30;在二维数组中为行下标为0 列下标为0

for(int i=0;i<15;i++){
            for(int j=0;j<15;j++){
                chess ch=new chess((j+1)*30,(i+1)*30)
                xy[i][j]=ch;
            }               
        }

**行列下标和棋子坐标对应关系为:
i=xy[][].Y/30-1; j=xy[][].X/30-1;**

如何让棋子在棋盘上出现呢?我们首先要用setGraphics()方法获得棋盘上的“画笔”g,
在设置为对应的白色或黑色之后
然后利用g.fillOval()方法在棋盘界面上画出白色棋子或黑色棋子。
当棋子出现在棋盘上之后,那么棋子的状态flag属性就应该从“0”(没有落子)转变为“1”(白棋)或“2”(黑棋)
在这里还应当设置一个变量color,用来记录和判断当前下的是白棋还是黑棋,假设用color为“1”代表当前下的是白棋,color为“2”代表当前下的是黑棋。在下完黑棋之后应当把color置为“1”,下次就下白棋,下完白棋之后把color设置为“2”,下次就下黑棋。

下完棋子之后呢?

我们在下完棋子之后就应当判断是否有五颗同颜色棋子相连了,我们不需要遍历整个棋盘去判断,只需要在最后落子的地方,从横向,竖向,正对角线,反对角线四个大方向上去判断是否有相同颜色的棋子连成一条线。
先上这部分代码

/*
 * 方法的参数是棋子对象
 */
public void checkChess(chess ch){
        //实例化一个弹窗对象,后面用来提白方还是黑方获胜
        JOptionPane op=new JOptionPane();
        /*
         * 初始化变量用来存储在 水平 垂直 正对角线 反对角线方向上的连续棋子
         */
        int count1=1;
        int count2=1;
        int count3=1;
        int count4=1;
        /*
         * 将棋子的坐标值 转换为对应的数组下标值 xy[0][0] 的坐标是(30 ,30)xy[0][1]的坐标是(60,30)
         */
        int x=ch.Y/30-1;   //行坐标
        int y=ch.X/30-1;   //列坐标
        /*
         * 水平方向上的检测
         */
        for(int j=y+1;j<15;j++){                                //行坐标不变 列坐标递增 检测ch右边的落子情况
            if(xy[x][y].flag==xy[x][j].flag){ //如果ch右边的棋子和ch颜色一样 计数加一
                count1++;
        }/如果ch右边的棋子和ch颜色不一样 则退出计数
            else
                break;                                          //如果不是的话退出判断
        }
        for(int j=y-1;j>=0;j--){                                //行坐标不变 列坐标递减 检测ch左边的落子情况
            if(xy[x][y].flag==xy[x][j].flag){
                count1++;
            }
            else
                break;
        }
        //水平方上的落子情况检测完
        if(count1>=5){                                  
            if(xy[x][y].flag==1)
                op.showMessageDialog(null, "白棋胜出"); 
            else
                op.showMessageDialog(null, "黑棋胜出"); 
        }
        /*
         * 垂直方向上的检测
         */
        for(int i=x-1;i>=0;i--){                                //列坐标不变 行坐标递减 检测ch上面的落子情况       
            if(xy[x][y].flag==xy[i][y].flag&&xy[x][y].flag!=0){
                count2++;
            }
            else
                break;
        }                                                       //列坐标不变 行坐标递加  检测ch下面的落子情况  
        for(int i=x+1;i<15;i++){                                
            if(xy[x][y].flag==xy[i][y].flag&&xy[x][y].flag!=0){
                count2++;
            }
            else
                break;
        }
        // 垂直方向上的棋子情况检测完
        if(count2>=5){                                  
            if(xy[x][y].flag==1)
                op.showMessageDialog(null, "白棋胜出"); 
            else
                op.showMessageDialog(null, "黑棋胜出"); 
        }
        /*
         * 正对角线上面的检测
         */
        for(int i=x-1,j=y+1;i>=0&&j<15;i--,j++){                // 行递减 列递加
            if(xy[x][y].flag==xy[i][j].flag&&xy[x][y].flag!=0){
                count3++;
            }
            else break;
        }
        for(int i=x+1,j=y-1;j>=0&&i<15;j--,i++){                //行递加 列递减
            if(xy[x][y].flag==xy[i][j].flag&&xy[x][y].flag!=0){
                count3++;
            }
            else break;
        }
        //正对角线上检测完毕
        if(count3>=5){
            if(xy[x][y].flag==1)
                op.showMessageDialog(null, "白棋胜出"); 
            else
                op.showMessageDialog(null, "黑棋胜出");
        }
        /*
         * 反对角线上的检测     
         */
        for(int i=x+1,j=y+1;i<15&&j<15;i++,j++){                //行递加列递加
            if(xy[x][y].flag==xy[i][j].flag&&xy[x][y].flag!=0){
                count4++;
            }
            else break;
        }
        for(int i=x-1,j=y-1;j>=0&&i>=0;j--,i--){
            if(xy[x][y].flag==xy[i][j].flag&&xy[x][y].flag!=0){
                count4++;
            }
            else break;
        }
        //反对角线上检测完毕
        if(count4>=5){
            if(xy[x][y].flag==1)
                op.showMessageDialog(null, "白棋胜出"); 
            else
                op.showMessageDialog(null, "黑棋胜出");
        }
    }

如何实现按键点击和落子?

当我们是实现了界面之后,理所应当的,接下来就是实现点击按键和落子的功能了,如何达到在点击按键和落子之后五子棋界面会有相应的反应呢?这需要我们用到事件监听机制,为按键加上监听。
按键点击的事件监听,我们要用到ActionListener接口。
在棋盘上落子实际上就是点击棋盘,棋盘上相应的位置画出棋子。我们可以用到MouseAdapter适配器
定义一个继承了MouseAdapter适配器实现了ActionListenner接口的事件监听类listener
给出对应部分代码

package com.ly.fiveChessV2;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashMap;

import javax.swing.JOptionPane;
import javax.swing.JPanel;

/*
 * 点击按钮 点击棋盘面板
 */
public class listener extends MouseAdapter implements ActionListener{
    int mode;
    int x,y;                    //x y是鼠标在棋盘界面上获得的坐标
    private Graphics2D g;       //画笔用来绘图
    int chesscount;             //连成一条线的同一颜色棋子数量
    public chess [][]xy;        //定义一个棋子数组
    int col=1;                  //定义一个颜色标志位 1:白色2:黑色
    chess chessnew=new chess(); //用一个棋子代表最近下的棋
    public JPanel panel;
    /*
     * 将棋盘上的画笔g赋值给属性g
     */
    public void setG(Graphics g){
        this.g=(Graphics2D)g;
    }
    /*
     * 把棋盘面板对象传过来
     */
    public void setP(JPanel panel){
        this.panel=panel;
    }
    /*
     * 将棋子数组传入
     */
    public void setChess(chess [][]xy){
        this.xy=xy;
    }
    /*
     *处理按键事件
     */
    public void actionPerformed(ActionEvent e){
        JOptionPane op=new JOptionPane();
        String str= e.getActionCommand();
        /*
         * 认输按键
         */
        if(str.equals("认输")){
            if(col==1){
            op.showMessageDialog(null, "白棋认输,黑棋胜"); 
            }
            else{
                op.showMessageDialog(null, "黑棋认输,白棋胜");     
            }
            for(int i=0;i<15;i++){
                for(int j=0;j<15;j++){
                    xy[i][j].flag=0;
                }
            }
            panel.paint(g);
        }
        /*
         * 悔棋按键
         */
        if(str.equals("悔棋")){               //悔棋应该是利用棋盘界面的重画paint()方法
            if(chessnew.flag==1){
                col=1;
                System.out.println("悔棋的是白棋,白棋再落一子");
            }
            else if(chessnew.flag==2){
                col=2;
                System.out.println("悔棋的是黑棋,黑棋再落一子");
            }
            chessnew.flag=0;                //把最近一次的棋子抹除掉
            panel.paint(g);
            for(int i=0;i<15;i++){
                for(int j=0;j<15;j++){
                    if(xy[i][j].flag!=0){
                        if(xy[i][j].flag==1){
                            g.setColor(Color.white);
                            g.fillOval(xy[i][j].X-10, xy[i][j].Y-10,20,20);
                        }
                        else{

                            g.setColor(Color.black);
                            g.fillOval(xy[i][j].X-10, xy[i][j].Y-10,20,20);
                        }
                    }
                }
            }
            System.out.println("悔棋");
        }
        if(str.equals("人人对战")){
            mode=11;
        }
        if(str.equals("人机对战")){
            mode=12;
        }
    }
    /*
     * 处理鼠标点击事件
     */
    public void mouseClicked(MouseEvent e) {
        /*
         * 画笔抗锯齿
         */
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        /*
         * 获取鼠标点击的x和y坐标
         */
        x=e.getX();
        y=e.getY(); 
        /*
         * 由鼠标的位置 得到棋子圆心该放的位置
         */
            for(int i=0;i<15;i++){
                for(int j=0;j<15;j++){                      //循环遍历数组找到鼠标点击的最近的格子
                    if(Math.abs(x-xy[i][j].X)<10&&Math.abs(y-xy[i][j].Y)<10){
                        if(xy[i][j].flag==0){               //判断点击处是否没有落过子
                            if(col == 1){                   //判断棋子该下的颜色
                                g.setColor(Color.white);
                                System.out.println("white");
                                g.fillOval(xy[i][j].X-10, xy[i][j].Y-10,20,20);
                                xy[i][j].flag=1;            //flag为1表示下的是白棋
                                chessnew=xy[i][j];          //将这一步下的棋保存起来
                                col=2;                      //下一次下黑旗
                            }
                            else if(col==2){
                                g.setColor(Color.black);
                                System.out.println("black");
                                g.fillOval(xy[i][j].X-10, xy[i][j].Y-10,20,20);
                                xy[i][j].flag=2;            //flag为1表示下的是黑旗
                                col=1;                      //下一次下白棋            
                            }
                        checkChess( xy[i][j]);
                        // 落完子 判断输赢之后 电脑落子 判断输赢

                        }   
                        else                                //已经有棋子落下过
                        System.out.println("这里不能落子");
                    }
                }
            }
        }
    }
}

在写完事件监听类之后我们应该实例化一个事件监听类对象,并为按键和棋盘添加事件监听。
附上相关代码

        /*
         * 实例化一个监听对象
         * 为各个组件加上监听
         */
        listener l=new listener();
        l.setG(g);
        l.setP(this);
        l.setChess(xy);
        this.addMouseListener(l);
        bquit.addActionListener(l);
        bundo.addActionListener(l);
        bstart.addActionListener(l);
        bpvp.addActionListener(l);
        bpvr.addActionListener(l);
        this.setG(g);                   //棋盘对象设置Graphics属性

有了以上代码我们的五子棋就能实现人人对战的功能。

如何实现人机对战?

要实现人机对战,那么就要让电脑知道棋子该下到哪一个位置,我们可以通过计算每一个位置上隐形棋子的权值(只有没下过的棋子才需要考虑)。电脑优先下权值大的棋子,然后判断一次输赢。

如何确定棋子的权值?

我的方法是用一个字符串记录棋子水平方向的、竖直方向上的、正对角线方向上、反对角线方向上的落子情况。然后根据落子情况,给该棋子赋值。
我们先要给出隐形棋子各个方向上可能的情况,和这种情况对应的权值。
我们可以利用哈希表实现

//首先实例化一个哈希表对象
 HashMap<String,Integer> hm = new HashMap<String,Integer>();

隐形棋子为“0”,白子为“1”,黑子为“2”;五子棋的Java实现 详解_第2张图片
上图对应的字符串即为“2022”(黑子、隐形棋子、黑子、黑子)

hm.put("2022",10);

我把上图中情况的棋子的权值设置为10,当我们以后检测到隐形棋子周围的落子情况之后,就能取出对应的权值。
比如字符串S为“2022”;

int value=hp.get(S);

那么value的值就是10;
当我们把一个隐形棋子的水平、竖直、正对角线、斜对角线方向上的情况全都统计完并把四个方向上的权值相加,得到该棋子最终的权值,下面给出计算权值的代码方法caculate()

public void caculate(chess ch){
        String str="0";     //用一个字符串来记录该棋子旁边的落子情况
        int x=ch.Y/30-1;    //把ch棋子对应的横纵坐标转换成在棋子数组里的行和列
        int y=ch.X/30-1;    

        hashInit();

        /*
         * 计算该位置棋子的权值
         * 参数为一个棋子 棋子flag有三种状态 0:还没有落子 1:落白子 2:落黑子
         */
        if(ch.flag==0){                 //只有没有当棋子没有落下的时候才要计算该棋子的权值
            Integer val;
             for(int j=y+1;j<15;j++){   //记录棋子右边的落子情况 是列在变
                if(xy[x][j].flag==0){   //该棋子右边没有落子
                    break;              //不用记录直接退出遍历循环
                }
                else 
                    if(xy[x][j].flag==1){
                        str=str+1;  //str在左边 往右加
                    }
                    else if(xy[x][j].flag==2){
                        str=str+2;  //str在左边 往右加
                        break;
                    }
            }

            // 水平方向上检测棋子 往左看
            for(int j=y-1;j>=0;j--){
                if(xy[x][j].flag==0){   //该棋子左边没有落子
                    break;              //不用记录直接退出遍历循环
                }
                else if(xy[x][j].flag==1){
                    str=1+str; //str在右边 往左加
                }
                else if(xy[x][j].flag==2){
                    str=2+str;  //str在右边 往左加
                    break;
                }
            }
             // 到这里之后棋子ch的左右情况就统计完了 str代表统计情况 利用str在哈希表对象中得到对应的键值
             val=hm.get(str);
            System.out.println("水平方向:"+x+"行"+y+"列棋子 str:"+str);
            if(val!=null){
                xy[x][y].value+=val;  //把对应的键值加到棋子中去
            }
            str="0";
            //竖直方向上 往上看
            for(int i=x-1;i>=0;i--){
                if(xy[i][y].flag==0){
                    break;
                }
                else if(xy[i][y].flag==1){
                    str=1+str;
                }
                else if(xy[i][y].flag==2){
                    str=2+str;
                    break;
                }
            }
            //竖直方向上 往下看
            for(int i=x+1;i<15;i++){
                if(xy[i][y].flag==0){
                    break;
                }
                else if(xy[i][y].flag==1){
                    str=str+1;
                }
                else if(xy[i][y].flag==2){
                    str=str+2;
                    break;
                }
            }
            System.out.println("竖直方向:"+x+"行"+y+"列棋子 str:"+str);
            val=hm.get(str);
                if(val!=null){
                    xy[x][y].value+=val;
                }
            str="0";
            //正对角线方向上 向上
            for(int i=x-1,j=y+1;i>=0&&j<15;i--,j++){
                    if(xy[i][j].flag==0){
                        break;
                    }
                    else if(xy[i][j].flag==1){
                        str=1+str;
                    }
                    else if(xy[i][j].flag==2){
                        str=2+str;
                        break;
                    }

            }
            //正对角线方向上 向下
            for(int i=x+1,j=y-1;i<15&&j>=0;i++,j--){
                    if(xy[i][j].flag==0){
                        break;
                    }
                    else if(xy[i][j].flag==1){
                        str=str+1;
                    }
                    else if(xy[i][j].flag==2){
                        str=str+2;
                        break;
                    }

            }
            System.out.println("正对角线上"+x+"行"+y+"列棋子str:"+str);
            val=hm.get(str);
            if(val!=null)
                xy[x][y].value+=val;
            str="0";
            //反对角线方向上 向上
            for(int i=x-1,j=y-1;i>=0&&j>=0;i--,j--){
                    if(xy[i][j].flag==0){
                        break;
                    }
                    else if(xy[i][j].flag==1){
                        str=1+str;
                    }
                    else if(xy[i][j].flag==2){
                        str=2+str;
                        break;
                    }       
            }
            //反对角线方向上 向下
            for(int i=x+1,j=y+1;i<15&&j<15;i++,j++){
                    if(xy[i][j].flag==0){
                        break;
                    }
                    else if(xy[i][j].flag==1){
                        str=str+1;
                    }
                    else if(xy[i][j].flag==2){
                        str=str+2;
                        break;
                    }
            }
            System.out.println("反对角线上"+x+"行"+y+"列棋子str:"+str);
            val=hm.get(str);
            if(val!=null)
                xy[x][y].value+=val;
            str="0";
            System.out.println(x+"行"+y+"列棋子权值:"+xy[x][y].value);
        }
    }

有了计算一个棋子权值的方法那么,接下来然计算机决定在哪里落子就很容易了。我们可以再写一个方法AI(),循环遍历棋子数组,在隐形棋子里找出权值最大的一个棋子,然后落子。

public void AI(){
        int x,y;
        // 定义一个棋子变量
        chess ch =new chess();
        //遍历二维棋子数组 计算出每一个未落子棋子权值
        for(int i=0;i<15;i++){
            for(int j=0;j<15;j++){
                System.out.println("计算"+i+"行"+j+"列 棋子");
                caculate(xy[i][j]);
            }
        }
        //遍历整个二维棋子数组,找出权值最大的棋子  
        for(int i=0;i<15;i++){
            for(int j=0;j<15;j++){
                if(xy[i][j].value>=ch.value){
                    ch=xy[i][j];
                }
            }
        }
        System.out.println("权值最大的棋子 "+(ch.Y/30-1)+"行"+(ch.X/30-1)+"列");
        //落子权值最大的棋子
        x=ch.Y/30-1;
        y=ch.X/30-1;
        xy[x][y].flag=2;
        g.setColor(Color.black);
        g.fillOval(xy[x][y].X-10, xy[x][y].Y-10,20,20);
        //清空棋子的权值
        for(int i=0;i<15;i++){
            for(int j=0;j<15;j++){
                xy[i][j].value=0;
            }
        }
    }

哈希表中五子棋的情况怎么给?

有人可能会说,下一盘五子棋那么多的棋子,怎么事先给出棋子的落子情况,和设置对应的落子情况呢?
其实 五子棋的落子情况需要考虑的不过是 活二 跳二 活三 眠三 活四 眠四之类的
我在这里给出活二 跳二 活三 眠三 活四 眠四之类相关介绍的链接 http://game.onegreen.net/wzq/HTML/142336.html

好了到这里最主要的代码已经讲解完了,大家要是有什么不清楚的地方可以给我留言。

你可能感兴趣的:(Java)