You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中使用ArrayList绘制不重叠圆形时出现Stack Overflow Error

解决Stack Overflow错误与不重叠圆形生成问题

你遇到的Stack Overflow错误,核心原因是CheckDistance方法的无限递归调用——当随机生成的坐标一直和上一个圆形重叠时,递归会无限进行,直到栈内存耗尽。除此之外,你的距离检查逻辑也有问题:当前只和最后一个生成的圆形比较,还是会出现和更早生成的圆形重叠的情况,而且random.nextInt()可能生成负数,导致圆形跑到面板外面。

下面一步步帮你解决这些问题:

问题分析

  • 递归无终止保障:CheckDistance用递归重试生成坐标,但如果随机数一直命中重叠区域,递归永远不会停止,直接触发栈溢出。
  • 检查逻辑不完整:只和最后一个生成的圆形比较,忽略了之前所有已存在的圆形,无法保证全局不重叠。
  • 随机数范围错误:random.nextInt()返回的是整个int范围的随机数,包括负数,生成的圆形可能出现在面板可视区域外。

解决方案

1. 把递归改成循环

用while循环代替递归,避免栈溢出问题,循环直到生成符合条件的坐标。

2. 完善距离检查逻辑

新生成的坐标需要和所有已添加到列表中的Country进行重叠检查,而不是只和最后一个。

3. 限制随机数范围

确保生成的坐标在面板可视区域内,同时预留圆形的大小和间距,避免超出边界。

修改后的完整代码

import javax.swing.*;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Algo {
    public static void main(String[] args) {
        new Algo();
    }

    public Algo() {
        EventQueue.invokeLater(() -> {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                ex.printStackTrace();
            }
            JFrame frame = new JFrame("Airport");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(new CountriesPane());
            frame.setSize(700, 700);
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }

    public class CountriesPane extends JPanel {
        private final List<Country> countries = new ArrayList<>(100);
        private final Random random = new Random();
        private static final int PANEL_WIDTH = 700;
        private static final int PANEL_HEIGHT = 700;

        public CountriesPane() {
            for (int index = 0; index < 50; index++) {
                countries.add(createNonOverlappingCountry());
            }
        }

        private Country createNonOverlappingCountry() {
            Country newCountry;
            boolean isOverlapping;
            do {
                // 生成在面板内的随机坐标,预留圆形大小和间距
                int x = random.nextInt(PANEL_WIDTH - Country.SIZE - Country.SPACE);
                int y = random.nextInt(PANEL_HEIGHT - Country.SIZE - Country.SPACE);
                newCountry = new Country(x, y);
                // 检查是否和已有的所有圆形重叠
                isOverlapping = false;
                for (Country existing : countries) {
                    if (isOverlapping(newCountry, existing)) {
                        isOverlapping = true;
                        break;
                    }
                }
            } while (isOverlapping);
            return newCountry;
        }

        // 检查两个圆形是否重叠(包括边缘接触)
        private boolean isOverlapping(Country a, Country b) {
            double dx = a.getX() - b.getX();
            double dy = a.getY() - b.getY();
            // 两个圆形的中心距离 <= 半径之和 + 间距
            double minDistance = Country.SIZE + Country.SPACE;
            return Math.sqrt(dx * dx + dy * dy) <= minDistance;
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            for (Country country : countries) {
                country.paint(g2d);
            }
            g2d.dispose();
        }
    }

    public static class Country {
        public static final int SIZE = 20;
        public static final int SPACE = 10;
        private final Ellipse2D shape;

        public Country(int x, int y) {
            shape = new Ellipse2D.Double(x, y, SIZE, SIZE);
        }

        public double getX() {
            return shape.getX() + SIZE / 2.0; // 返回中心X坐标
        }

        public double getY() {
            return shape.getY() + SIZE / 2.0; // 返回中心Y坐标
        }

        public void paint(Graphics2D g2d) {
            g2d.setColor(Color.BLUE);
            g2d.fill(shape);
        }
    }
}

关键修改点说明

  • 用循环替代递归:createNonOverlappingCountry方法用do-while循环生成坐标,直到找到不重叠的位置,彻底避免栈溢出。
  • 全局重叠检查:每次生成新圆形时,遍历已有的所有圆形,用中心距离法判断是否重叠(更准确的圆形重叠判断方式)。
  • 固定常量与封装:把圆形大小、间距定义为Country类的静态常量,同时给Country添加获取中心坐标的方法,让逻辑更清晰。
  • 边界控制:生成随机坐标时,减去圆形大小和间距,确保圆形完全在面板可视区域内。
  • 代码规范:修正了变量命名(比如Countries改成countries,符合Java驼峰命名规范),提升代码可读性。

这样修改后,不仅解决了Stack Overflow问题,还能真正生成50个不重叠的圆形,同时方便后续对每个Country对象进行操作。

内容的提问来源于stack exchange,提问作者TheGrimBoo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:03:51