Java Stack Overflow 已经折磨我很久了

标签 java stack-overflow

我刚刚加入这个很棒的社区,但我很遗憾地承认我在这里的第一篇帖子与一个痛苦的错误有关。当我在做我的家庭作业时,一个 brickbreaker oop uni 项目,我遇到了各种错误。到目前为止的故事:

  • 我必须创建一个继承 JButton 功能的抽象 Brick 类,它支持一个抽象方法,我称之为 brickSpecialAction(),由各种积木子类(百搭积木、随机积木、彩色积木)实现。<
  • 我还必须创建一个 Grid 类,它继承 JFrame 并为游戏添加棋盘功能,并将该功能扩展到每次用户没有可用的移动和超过分数阈值时更改级别,就像 ActionListener每次我按其中一 block 积木等等
  • 除了这些类之外,我还有一些次要类,例如关卡,它们支持游戏,但不会做任何戏剧性的事情,也不会做任何与到目前为止的错误有关的事情。
  • 错误从何而来:在创建 Brick 的第一个子类 ColourBrick 时,它是一种具有背景颜色的砖 block ,我必须提供 brickSpecialAction 方法的实现,这将是每当我按下那种类型的砖 block 时,监听器类 (Grid) 就会调用它。起初,该方法以空指针异常折磨着我可怜的灵魂。在对代码进行进一步研究和改进后,我想出了一个解决方案,该解决方案看似可行,但实际上只是一个更大的困惑源:它没有正确执行,给我留下了一个 StackOverflowError。<

到目前为止的类(class):

基础砖类

package gr.teicrete.epp.ooplab.brickbreaker;

import java.awt.Color;
import java.awt.Container;
import java.awt.Point;
import javax.swing.JButton;
import javax.swing.JFrame;

/**
 * The Brick class will provide general functionality to our bricks.
 *
 * @author Fokis
 */
public abstract class Brick extends JButton{

    private Point brickPosition; // The brick's position
    private Container cont;

    /**
     * The Brick constructor used to initialize the bricks. Not really used as
     * we cannot instantiate the brick class, being abstract and such.
     *
     * @param posx The brick's x position
     * @param posy The brick's y position
     */
     public Brick(int posx, int posy) {
        this.brickPosition = new Point(posx, posy);
        this.setVisible(true);
     }

     /**
      * The public accessor method to the brick's position
      * @return The brick's position
      */
      public Point getBrickPosition() {
         return this.brickPosition;
      }

     /**
      * The public accessor method to the brick's container.
      *
      * @return The grid's container.
      */
      public Grid getContainer() {
         return (Grid) this.cont;
      }

      public abstract int brickSpecialAction(Brick brickie);
 }

基本的 ColourBrick 类:

package gr.teicrete.epp.ooplab.brickbreaker;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.util.Random;

/**
 * The ColourBrick class provides functionality to the colourful bricks.
 *
 * @author Fokis
 */
 public class ColourBrick extends Brick {

/**
 * The constructor used to initialize our colour bricks.
 *
 * @param posx The x position of the brick. Used for indexing later.
 * @param posy The y position of the brick. Used for indexing later.
 * @param seed The seed to the random number generator, so as to pick
 * colours available at each level.
 */
public ColourBrick(int posx, int posy, int seed) {
    super(posx, posy);
    this.setBackground(this.pickColour(seed));
    this.setPreferredSize(new Dimension(50, 44));
}

/**
 * Public method used to initialise our bricks with a colour.
 *
 * @param seed the initial seed we provide to the random number generator
 * @return The color of the brick to be initialized.
 */
 public Color pickColour(int seed) {

    Random randomColour = new Random(); // A random object, for RNG
    Color assignedColor; // Used to store the color we picked

    int potentialColour = randomColour.nextInt(seed); // Picking a random num

    switch (potentialColour) {
        case 0:
            assignedColor = Color.RED;
            break;
        case 1:
            assignedColor = Color.CYAN;
            break;
        case 2:
            assignedColor = Color.GREEN;
            break;
        case 3:
            assignedColor = Color.YELLOW;
            break;
        case 4:
            assignedColor = Color.PINK;
            break;
        case 5:
            assignedColor = Color.MAGENTA;
            break;
        case 6:
            assignedColor = Color.BLACK;
            break;
        case 7:
            assignedColor = Color.ORANGE;
            break;
        case 8:
            assignedColor = Color.GREEN;
            break;
        default:
            // Not really needed, but we provide it to ensure that the compiler
            // won't argue that assignedColor might be uninitialized
            assignedColor = null;
    }
    return assignedColor;
}

/**
 * The method used to destroy the bricks that we click on.
 *
 * @param brickie Used for the recursive calls of the method.
 * @return The total number of bricks destroyed.
 */
@Override
public int brickSpecialAction(Brick brickie) {

    int totalRemovedBricks = 0; // Used to calculate the total number of removed bricks

    this.setVisible(false); // Making it invisible
    totalRemovedBricks++; // Counting it as a brick destroyed, in order to calculate the score later

    Grid omnigrid = (Grid) this.getTopLevelAncestor();
    Point brickPosition = this.getBrickPosition();

    for (int i = 0; i < 4; i++) {
        switch (i) {
            case 0:
                // Checking to see if the brick above the one we have now has the same colour as the one we are in now
                if (omnigrid.getBrickByXAndY(brickPosition.x, brickPosition.y + 1).getBackground().equals(this.getBackground())) {
                    totalRemovedBricks += brickSpecialAction(omnigrid.getBrickByXAndY(brickPosition.x, brickPosition. y + 1));
                }
                break;
            case 1:
                // Checking to see if the brick beyond the one that we have now has the same colour as the one we are in now
                if (omnigrid.getBrickByXAndY(brickPosition.x, brickPosition.y - 1).getBackground().equals(this.getBackground())) {
                    totalRemovedBricks += brickSpecialAction(omnigrid.getBrickByXAndY(brickPosition.x, brickPosition.y - 1));
                }
                break;
            case 2:
                // Checking to see if the brick on the left of the one we have now has the same colour as the one we are in now
                if (omnigrid.getBrickByXAndY(brickPosition.x - 1, brickPosition.y).getBackground().equals(this.getBackground())) {
                    totalRemovedBricks += brickSpecialAction(omnigrid.getBrickByXAndY(brickPosition.x - 1, brickPosition.y));
                }
                break;
            case 3:
                // Checking to see if the brick on the right of the one we have now has the same colour as the one we are in now
                if (omnigrid.getBrickByXAndY(brickPosition.x + 1, brickPosition.y).getBackground().equals(this.getBackground())) {
                    totalRemovedBricks += brickSpecialAction(omnigrid.getBrickByXAndY(brickPosition.x + 1, brickPosition.y));
                }
                break;
        }
    }
    return totalRemovedBricks; // returning the total ammount of bricks destroyed used to calculate the score later
}
}

和网格类:

package gr.teicrete.epp.ooplab.brickbreaker;

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;

/**
 * The Grid class will provide objects that will be used as our board for the
 * game.
 *
 * @author Fokis
 */
 public class Grid extends JFrame implements ActionListener {

private Levels currentLevel; // A reference to the current level
private int generalHiscore; //  A variable storing the current HiScore
private float currentScore = 0.0f; // A variable storing the current Score
private int levelsElevated = 1; // A variable used to store the levels the player has elevated each time
private boolean changed;
private String playerName; // A variable used to store the current player's name

/**
 * The Grid constructor. Pretty much handles everything. From initialising
 * player score to filling the grid with bricks.
 *
 * @param playerName The current player's name.
 */
public Grid(String playerName) {
    super();
    this.currentLevel = new Levels(levelsElevated);
    this.generalHiscore = 0;
    this.currentScore = 0;
    this.playerName = playerName;
    this.setLayout(new GridLayout(currentLevel.getLevelRows(), currentLevel.getLevelColumns()));
    initialize();
    pack();

    this.setVisible(true);
    this.setTitle("Player name: " + playerName + " Current Score: " + currentScore + " Hiscore: " + currentLevel.getHiScore()); // To be reviewed.
    this.setDefaultCloseOperation(Grid.EXIT_ON_CLOSE);
}

/**
 * The method that will be invoked everytime we need to change the level
 *
 * @return Whether or not the method was successful.
 */
public boolean changeLevel() {
    levelsElevated++;
    this.currentLevel = new Levels(levelsElevated);
    this.setLayout(new GridLayout(currentLevel.getLevelRows(), currentLevel.getLevelColumns()));
    return true;
}

/**
 * The method that will be invoked everytime we need to see if the game
 * should change level, or if the player lost.
 */
public void checkState() {
    if (hasAvailableMoves() == false && isAboveScoreThreshold() == true) {
        changed = changeLevel();
    } else if (hasAvailableMoves() == false && isAboveScoreThreshold() == false) {
        System.out.println("What a pity. You lost.");
    }
}

/**
 * The method that will be used to calculate the score.
 *
 * @param removedBricks The total number of bricks removed each time. Used
 * to actually calculate the score.
 * @return The player's current score.
 */
public float calculateScore(int removedBricks) {
    if (removedBricks <= 4) {
        currentScore += removedBricks;
    } else if (removedBricks >= 5 && removedBricks <= 12) {
        currentScore += (removedBricks * 1.5);
    } else {
        currentScore += 2 * removedBricks;
    }

    if (currentScore > currentLevel.getHiScore()) {
        currentLevel.setHiScore(currentScore);
    }

    return currentScore;
}

/**
 * The method that will be used to check if the player is above each level's
 * winning score threshold.
 *
 * @return The current state of the player's score.
 */
public boolean isAboveScoreThreshold() {
    if (currentScore >= currentLevel.getLevelRequiredScore()) {
        return true;
    } else {
        return false;
    }
}

/**
 * The method that will be used to check if the player has available moves
 * left. Will later be used to check whether or not we should change level.
 * NOT YET IMPLEMENTED.
 *
 * @return Whether or not the player has available moves left
 */
public boolean hasAvailableMoves() {
    return true;
}

/**
 * The method that will be invoked everytime we need to parse one of the
 * bricks.
 *
 * @param x The x position of the brick
 * @param y The y position of the brick
 * @return The brick that we want to manipulate.
 */
public Brick getBrickByXAndY(int x, int y) {
    return (Brick) this.getContentPane().getComponent((y * this.currentLevel.getLevelRows()) + x);
}

/**
 * The method that will be invoked to actually fill our Grid with bricks.
 */
public void initialize() {

    int acceptedBricks; // To be used for calculation of acceptedBricks

    for (acceptedBricks = 0; acceptedBricks < currentLevel.getLevelTotalBricks(); acceptedBricks++) {
        for (int x = 1; x <= currentLevel.getLevelRows(); x++) {
            for (int y = 1; y <= currentLevel.getLevelColumns(); y++) {
                Brick newBrick = new ColourBrick(x, y, currentLevel.getLevelAvailableColours());
                newBrick.addActionListener(this);
                this.add(newBrick);
                acceptedBricks++;
            }
        }
    }
}

@Override
public void actionPerformed(ActionEvent evt) {
    Brick brickClicked = (Brick) evt.getSource();
    calculateScore(brickClicked.brickSpecialAction(brickClicked));
    this.setTitle("Player name: " + playerName + " Current Score: " + currentScore + " Hiscore: " + currentLevel.getHiScore());
    this.checkState();
}
}

重要说明:我不会便宜到向别人寻求项目或问题的解决方案,我只是希望有人向我解释为什么我会出现此错误。之后,我将尝试独自解决这个问题。但是请帮助我。我已经很努力了。

编辑:堆栈跟踪:

Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError
    at java.awt.Component.isVisible_NoClientCode(Component.java:1288)
    at java.awt.Component.isVisible(Component.java:1285)
    at javax.swing.JComponent.setVisible(JComponent.java:2639)
    at gr.teicrete.epp.ooplab.brickbreaker.ColourBrick.brickSpecialAction(ColourBrick.java:90)
    at gr.teicrete.epp.ooplab.brickbreaker.ColourBrick.brickSpecialAction(ColourBrick.java:101)
    at gr.teicrete.epp.ooplab.brickbreaker.ColourBrick.brickSpecialAction(ColourBrick.java:101)
    at gr.teicrete.epp.ooplab.brickbreaker.ColourBrick.brickSpecialAction(ColourBrick.java:101)
    at gr.teicrete.epp.ooplab.brickbreaker.ColourBrick.brickSpecialAction(ColourBrick.java:101)
    at gr.teicrete.epp.ooplab.brickbreaker.ColourBrick.brickSpecialAction(ColourBrick.java:101)
    at gr.teicrete.epp.ooplab.brickbreaker.ColourBrick.brickSpecialAction(ColourBrick.java:101)
    at gr.teicrete.epp.ooplab.brickbreaker.ColourBrick.brickSpecialAction(ColourBrick.java:101)
    at gr.teicrete.epp.ooplab.brickbreaker.ColourBrick.brickSpecialAction(ColourBrick.java:101)
    at gr.teicrete.epp.ooplab.brickbreaker.ColourBrick.brickSpecialAction(ColourBrick.java:101)
    at 

它会一直这样下去。

最佳答案

您的 brickSpecialAction() 方法包含对自身的调用。如果没有适当的控制,这会使您陷入无限递归循环。 StackOverflow 错误经常由此类情况引起。

关于Java Stack Overflow 已经折磨我很久了,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10824002/

相关文章:

java - 用于散列的 Hadoop Map Reduce 程序

java - Memcached 中的多个缓存

c# - 属性引起的 Stackoverflow 异常

Gradle : Stackoverflow Error

linux - 如何测试/验证 vmalloc 保护页在 Linux 中是否正常工作

java - 使用 M2Eclipse 插件在交互模式下使用 versions-maven-plugin 设置版本?

java - 将 url 编码数据转换为 json

java - 从 JFrame 中的 JFXPanel 打开 JavaFX 子对话框

java - 使用两个组件 Dagger2 时的 stackoverflow

java - Spring 数据存储库 StackOverflow