java小球碰撞生产一堆小球。

应该是随机位置生产一个小球,为什么会生产一堆呢?

package work;
import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.plaf.ComponentUI;
import java.util.*;
/**
 */
@SuppressWarnings("serial")
public class BallPanel extends JPanel
{
    public ArrayList<Ball> balls = new ArrayList<Ball>();  //小球列表
    public BallComponent component = new BallComponent();  //小球画板
    public JButton btnAdd = new JButton("增加");    //Add按钮
    public JComboBox placeCombo = new JComboBox(); //小球出现方位
    public BallThread thread = new BallThread();   //小球运动线程
    public int delay = 5;  //小球运动的延缓时间
    public double newX;
    public double newY;
    public Random rand = new Random();
    public int flag=0;
    /**
     * 初始化小球面板
     */
    public BallPanel()
    {
        setLayout(new BorderLayout());  //设置为BorderLayout的布局
        add(component, BorderLayout.CENTER);    //将小球画板加到面板中央
        component.setOpaque(true);              //设置画板不透明,以便能添加背景色
        component.setBackground(Color.white);   //设置背景色
        JPanel panel = new JPanel();    //创建用来放各种按钮的面板
        panel.add(btnAdd);              //将Add按钮放入该面板
        panel.setBackground(Color.LIGHT_GRAY);
        add(panel, BorderLayout.SOUTH); //将按钮面板加到主面板南部
        //Add按钮加入监听器,当按下按钮时添加小球
        btnAdd.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent event)
            {
                component.addBall();
            }
        });
        thread.start(); //画画板的线程开始
    }

    /**
     * 主函数,主要用于测试
     * 
     */
    public static void main(String[] args){
        EventQueue.invokeLater(new Runnable(){
            public void run(){
                JFrame frame = new JFrame("小球碰撞"); //设置测试框架的标题
                frame.add(new BallPanel());     //将小球碰撞动画面板放上去
                frame.setSize(700, 500);        //设置框架大小
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);   //设置框架的默认关闭方式
                frame.setLocationByPlatform(true);  //将框架的定位交给系统实现
                frame.setVisible(true);         //设置框架可见
            }
        });
    }

    /**
     * 小球运动线程
     * 
     */
class BallThread extends Thread{
	public boolean isStop = false; //停止标记

        /**
         * 线程体
         */
        public void run(){
            while (true){    //让它一直执行
                if (!isStop){   //当没有停止的时候
                	
                    for (int i = 0; i < balls.size(); i++)
                    {
                        balls.get(i).move(component.getBounds());//每个小球都移动一遍
                        
                    }
                    
                    if(flag==1){
                   
                    	component.addBall();
                    	flag=0;
                    }
                    component.repaint();    //重画画板
                }
                
                try {
                    Thread.sleep(delay);    //线程延缓delay毫秒
                } catch (InterruptedException e) {  //捕获异常
                    e.printStackTrace();    //处理异常
                }
                
                
                
            }
            
         }
          
        /**
         * 设置stop标志
         * @param isStop    是否停止
         */
		public void setStop(boolean isStop)
        {
            this.isStop = isStop;
        }
}


/**
 * 小球的画板
 * @author zjf
 */

class BallComponent extends JComponent{
        public BallComponent()
        {
            setUI(new ComponentUI()
            {
                public void installUI(JComponent c)
                {
                    super.installUI(c);
                    LookAndFeel.installColors(c, "Panel.background",
                            "Panel.foreground");
                }
            });
        }
        /**
         * 添加小球
         */
        public void addBall()
        {
            double x = rand.nextInt(200) + 20;   //小球开始的x坐标
            double y = rand.nextInt(200) + 20;   //小球开始的y坐标
            balls.add(new Ball(x, y)); //在小球的列表中加入新球,球的初始方位和颜色为前面的值
        }

        /**
         * 绘制画板
         */
        public void paintComponent(Graphics g)
        {
            super.paintComponent(g);
            Graphics2D g2 = (Graphics2D)g;
            for (int i = 0; i < balls.size(); i++)   //将小球列表中的小球都画到画板上
            {
                Ball ball = balls.get(i);
                g2.fill(ball.getShape());       //画出小球的形状
            }
        }
}

    /**
     * 小球类
     * @author zjf
     */
public class Ball
    {
		public static final double SIZE = 20;  //小球的直径
		public double x;   //小球所在的x坐标
		public double y;   //小球所在的y坐标
		public double vx = Math.sqrt(2) / 2;   //小球在x轴的速度
        public double vy = Math.sqrt(2) / 2;   //小球在y轴的速度
        public Color color = Color.BLACK;      //小球的颜色

        /**
         * 小球的构造函数
         * @param x 小球所在的x坐标
         * @param y 小球所在的y坐标
         */
        public Ball(double x, double y)
        {
            this.x = x;
            this.y = y;
        }

        /**
         * 小球在一个矩形边框中移动
         * @param bounds 矩形边框
         */
        public void move(Rectangle2D bounds)
        {
            x += vx;    //小球在x轴上的位移
            y += vy;    //小球在y轴上的位移
            double minX = bounds.getMinX(); //矩形边界的最小x坐标
            double minY = bounds.getMinY(); //矩形边界的最小y坐标
            double maxX = bounds.getMaxX(); //矩形边界的最大x坐标
            double maxY = bounds.getMaxY(); //矩形边界的最大y坐标
            if (x <= minX)   //如果小球越过左边界
            {
                x = minX;   //小球的x坐标变为矩形边界的最小x坐标
                vx = -vx;   //小球在x轴方向的速度反向
            }
            if (y <= minY)   //如果小球越过上边界
            {
                y = minY;   //小球的y坐标变为矩形边界的最小y坐标
                vy = -vy;   //小球在y轴方向的速度反向
            }
            if (x + SIZE >= maxX)    //如果小球越过右边界
            {
                x = maxX - SIZE;    //小球的x坐标变为矩形边界的最大x坐标减去小球的直径
                vx = -vx;           //小球在x轴方向的速度反向
            }
            if (y + SIZE >= maxY)    //如果小球越过下边界
            {
                y = maxY - SIZE;    //小球的y坐标变为矩形边界的最大y坐标减去小球的直径
                vy = -vy;           //小球在y轴方向的速度反向
            }
            /*
             * 
             * 判断小球间是否发生碰撞
             */
            for (int i = 0; i < balls.size(); i++)
            {
                Ball ball = balls.get(i);
                if (this.equals(ball))
                    continue;
                if ((ball.x - x) * (ball.x - x) + (ball.y - y) * (ball.y - y) <= SIZE * SIZE)    //当两球间的距离小于直径时,可认为两小球发生了碰撞
                {
                    flag=1;
                    double degree = Math.atan((y - ball.y) / (x - ball.x)); //获取自己与发生碰撞的小球之间所形成的夹角,因为夹角只能在-pi/2-pi/2之间,所以还需判断两球的x坐标之间的关系
                    if (x > ball.x)      //如果自己的x坐标大于发生碰撞的小球的x坐标,由数学知识可知自己应该往正向运动
                    {
                        vx = Math.cos(degree);
                        vy = Math.sin(degree);
                    }
                    else    //如果自己的x坐标小于发生碰撞的小球的x坐标,由数学知识可知应该朝负向运动
                    {
                        vx = -Math.cos(degree);
                        vy = -Math.sin(degree);
                    }
                  
                }
            }
        }

        /**
         * 获取小球的形状
         * @return 形状
         */
        public Ellipse2D getShape()
        {
            return new Ellipse2D.Double(x, y, SIZE, SIZE);
        }
        /**
         * 判断两个小球是否相同
         */
        public boolean equals(Object object) {
            if (this == object) return true;    //如果所指的对象相同,即两小球的确相同
            if (object == null) return false;   //如果要比较的小球不存在,则两小球不同
            if (getClass() != object.getClass()) return false;  //如果自己的类名与另一个对象的类名不同,则两小球不同
            Ball ball = (Ball) object;           //将另一个对象强制转化为小球
            return x == ball.x && y == ball.y && color.equals(ball.color);  //通过方位,颜色判断是否相同
        }
    }
}

 

public BallPanel()
    {
        setLayout(new BorderLayout());  //设置为BorderLayout的布局
        add(component, BorderLayout.CENTER);    //将小球画板加到面板中央
        component.setOpaque(true);              //设置画板不透明,以便能添加背景色
        component.setBackground(Color.white);   //设置背景色
        JPanel panel = new JPanel();    //创建用来放各种按钮的面板
        panel.add(btnAdd);              //将Add按钮放入该面板
        panel.setBackground(Color.LIGHT_GRAY);
        add(panel, BorderLayout.SOUTH); //将按钮面板加到主面板南部
        //Add按钮加入监听器,当按下按钮时添加小球
        btnAdd.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent event)
            {
                component.addBall();
            }
        });
        thread.start(); //画画板的线程开始
    }
 
    /**
     * 主函数,主要用于测试
     * 
     */
    public static void main(String[] args){
        EventQueue.invokeLater(new Runnable(){
            public void run(){
                JFrame frame = new JFrame("小球碰撞"); //设置测试框架的标题
                frame.add(new BallPanel());     //将小球碰撞动画面板放上去
                frame.setSize(700, 500);        //设置框架大小
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);   //设置框架的默认关闭方式
                frame.setLocationByPlatform(true);  //将框架的定位交给系统实现
                frame.setVisible(true);         //设置框架可见
            }
        });
    }
 
    /**
     * 小球运动线程
     * 
     */
class BallThread extends Thread{
    public boolean isStop = false; //停止标记
 
        /**
         * 线程体
         */
        public void run(){
            while (true){    //让它一直执行
                if (!isStop){   //当没有停止的时候
                    
                    for (int i = 0; i < balls.size(); i++)
                    {
                        balls.get(i).move(component.getBounds());//每个小球都移动一遍
                        
                    }
                    
                    if(flag==1){
                   
                        component.addBall();
                        flag=0;
                    }
                    component.repaint();    //重画画板
                }
                
                try {
                    Thread.sleep(delay);    //线程延缓delay毫秒
                } catch (InterruptedException e) {  //捕获异常
                    e.printStackTrace();    //处理异常
                }
                
                
                
            }
            
         }
          
        /**
         * 设置stop标志
         * @param isStop    是否停止
         */
        public void setStop(boolean isStop)
        {
            this.isStop = isStop;
        }
}
 
 
/**
 * 小球的画板
 * @author zjf
 */
 
class BallComponent extends JComponent{
        public BallComponent()
        {
            setUI(new ComponentUI()
            {
                public void installUI(JComponent c)
                {
                    super.installUI(c);
                    LookAndFeel.installColors(c, "Panel.background",
                            "Panel.foreground");
                }
            });
        }
        /**
         * 添加小球
         */
        public void addBall()
        {