I keep on seeing the "Exception in thread "main" java.lang.StackOverflowError". I know this mainly pops up because of recursion however in my code I don't see how its being recursive. My main issue is that I really don't know how to fix this error.
I have three classes that I am using. I am using a main class called "mainIA" which I use to execute the code, then I have another class called "MainFrame" which extends "mainIA". Then I have "ServingButtons" class which extends "MainFrame" Class.
Here is my mainIA class code:
public static void main(String[] args) {
MainFrame frame = new MainFrame();
}
Here is my MainFrame class code (this is where the error is coming from.
package sweets;
import javax.swing.*;
import java.awt.*;
public class MainFrame extends JFrame {
//all the foods
String[] food = {bananaBread, brownies, chocolateChipcookies, macarons};
final static String bananaBread = "banana bread";
final static String brownies = "brownies";
final static String chocolateChipcookies = "chocolate chip cookies";
final static String macarons = "macarons";
public MainFrame(){
JPanel recipeName = new JPanel(); //this will have the JComboBox with the foodList
JLabel recipe = new JLabel("Recipes: ");
recipeName.setLayout(new FlowLayout());
recipeName.add(recipe);
JComboBox foodList = new JComboBox(food);
recipeName.add(foodList);
JLabel ingredients = new JLabel("Ingredients"); //this will have the dynamically changing ingredients
JLabel inputRecipe = new JLabel("Input Recipe"); //this will have the input recipe JTextField
this.setTitle("Recipe Portion Calculator");
this.setLayout(new GridLayout(4,1));
this.setSize(800,800);
this.add(recipeName);
this.add(new ServingButtons()); //<< IntelliJ identifies the error on this line
this.add(ingredients);
this.add(inputRecipe);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
}
Here is my ServingsButton class code:
package sweets;
import javax.swing.*;
import java.awt.*;
public class ServingButtons extends MainFrame {
public int servingNumber = 0;
//ingredient Volumes
public int almondFlourVol = 0;
public int allPurposeFlourVol = 0;
public int unsaltedButterVol = 0;
public int bakingSodaVol = 0;
public int bakingPowderVol = 0;
public int vanillaExtractVol = 0;
public int cocoaPowderVol = 0;
public int saltVol = 0;
public int chocolateChipsVol = 0;
public int instantEspressoVol = 0;
public int vegetableOilVol = 0;
public int bananasVol = 0;
//sugars
public int granulatedSugarVol = 0;
public int powderedSugarVol = 0;
public int lightBrownSugarVol = 0;
//eggs
public int eggsVol = 0;
public int eggWhitesVol = 0;
JLabel granulatedSugar = new JLabel("Granulated Sugar: " + (granulatedSugarVol));
JLabel powderedSugar = new JLabel("Powdered Sugar: " + (powderedSugarVol));
JLabel lightBrownSugar = new JLabel("Light Brown Sugar: " + (lightBrownSugarVol));
JLabel eggs = new JLabel("Eggs: " + (eggsVol));
JLabel eggWhites = new JLabel("Egg Whites: " + (eggWhitesVol));
JLabel bananas = new JLabel("Bananas: " + (bananasVol));
JLabel vegetableOil = new JLabel("Vegetable Oil: " + (vegetableOilVol));
JLabel instantEspresso = new JLabel("Instant Espresso: " + (instantEspressoVol));
JLabel chocolateChips = new JLabel("Chocolate Chips: " + (chocolateChipsVol));
JLabel salt = new JLabel("Salt: " + (saltVol));
JLabel cocoaPowder = new JLabel("Cocoa Powder: " + (cocoaPowderVol));
JLabel vanillaExtract = new JLabel("Vanilla Extract: " + (vanillaExtractVol));
JLabel bakingSoda = new JLabel("Baking Soda: " + (bakingSodaVol));
JLabel unsaltedButter = new JLabel("Unsalted Butter: " + (unsaltedButterVol));
JLabel allPurposeFlour = new JLabel("All-Purpose Flour: " + (allPurposeFlourVol));
JLabel almondFlour = new JLabel("Almond Flour: " + (almondFlourVol));
JLabel bakingPowder = new JLabel("Baking Powder: " + (bakingPowderVol));
JPanel servings = new JPanel();
public ServingButtons() {
servings.setLayout(new GridLayout(1, 4));
//used this code from this Quora Link: https://www.quora.com/How-would-I-get-my-program-to-add-1-every-time-I-press-the-button-%E2%80%9Da%E2%80%9D-in-Java
servings.add(new JLabel("Number of Servings: "));
JLabel counterLbl = new JLabel(Integer.toString(servingNumber));
JButton decButton = new JButton(("-"));
decButton.addActionListener(l -> {
counterLbl.setText(Integer.toString(--servingNumber));
almondFlour.setText("Almound Flour: " + (--almondFlourVol));
granulatedSugar.setText("Granulated Sugar: " + (--granulatedSugarVol));
powderedSugar.setText("Powdered Sugar: " + (--powderedSugarVol));
lightBrownSugar.setText("Light Brown Sugar: " +(--lightBrownSugarVol));
eggs.setText("Eggs: " + (--eggsVol));
eggWhites.setText("Egg Whites: " + (--eggWhitesVol));
bananas.setText("Bananas: " + (--bananasVol));
vegetableOil.setText("Vegetable Oil: " + (--vegetableOilVol));
instantEspresso.setText("Instant Espresso: " + (--instantEspressoVol));
chocolateChips.setText("Chocolate Chips: " + (--chocolateChipsVol));
salt.setText("Salt: " + (--saltVol));
cocoaPowder.setText("Cocoa Powder: " + (--cocoaPowderVol));
vanillaExtract.setText("Vanilla Extract: " + (--vanillaExtractVol));
bakingSoda.setText("Baking Soda: " + (--bakingSodaVol));
unsaltedButter.setText("Unsalted Butter: " + (--unsaltedButterVol));
allPurposeFlour.setText("All-Purpose Flour: " + (--allPurposeFlourVol));
bakingPowder.setText("All-Purpose Flour: " + (--bakingPowderVol));
});
JLabel space = new JLabel("");
servings.add(space);
servings.add(decButton);
servings.add(counterLbl);
JButton incButton = new JButton("+");
incButton.addActionListener(l -> {
counterLbl.setText(Integer.toString(++servingNumber));
granulatedSugar.setText("Granulated Sugar: " + (++granulatedSugarVol));
powderedSugar.setText("Powdered Sugar: " + (++powderedSugarVol));
lightBrownSugar.setText("Light Brown Sugar: " + (++lightBrownSugarVol));
eggs.setText("Eggs: " + (++eggsVol));
eggWhites.setText("Egg Whites: " + (++eggWhitesVol));
bananas.setText("bananas: " + (++bananasVol));
vegetableOil.setText("Vegetable Oil: "+ (++vegetableOilVol));
instantEspresso.setText("instant Espresso: " + (++instantEspressoVol));
chocolateChips.setText("Chocolate Chips: "+ (++chocolateChipsVol));
salt.setText("Salt: " + (++saltVol));
cocoaPowder.setText("Cocoa Powder: " + (++cocoaPowderVol));
vanillaExtract.setText("Vanilla Extract: " + (++vanillaExtractVol));
bakingSoda.setText("Baking Soda: " + (++bakingSodaVol));
unsaltedButter.setText("Unsalted Buttter: " + (++unsaltedButterVol));
allPurposeFlour.setText("All-Purpose Flour: " + (++allPurposeFlourVol));
almondFlour.setText("Almound Flour: " + (++almondFlourVol));
bakingPowder.setText("All-Purpose Flour: " + (++bakingPowderVol));
});
servings.add(incButton);
}
}
Any help would be greatly appreciated!
new ServingButtons()
does a lot:
First, we determine the full class hierarchy. Which is Object -> .... JFrame -> MainFrame -> ServingButtons
.
Then, going from Object
up to ServingButtons
, the JVM will run the instance initializers (here, all non-static fields that are initialized as they are declared by some non-constant value, such as JLabel granulatedSugar = new JLabel("Granulated Sugar: " + (granulatedSugarVol));
).
Then, the ServingButtons constructor is invoked.
Note that all constructors MUST start with a this()
or super()
statement. (in JDK22+ you no longer have to run it as first thing, but you still have to guaranteed run a this or super). That means any given constructor necessarily ends up invoking one of its parent class's constructor, and so on.
Thus, constructing a new ServingButtons
, given that it extends MainFrame
, it'll end up running MainFrame's constructor, which calls new ServingButtons()
, which ends up running MainFrame's constructor, which calls new ServingButtons()
, .... you get the point.
ServingButtons having extends MainFrame
on it is weird. I don't know what you thought that would accomplish, but, it doesn't - and it does cause that stack overflow.