Search code examples
javastack-overflowinfinite-looptostring

Why do I get StackOverflowError


This is my parent class with two methods named toString. The one with the parameter is used in the child class.

public abstract class Army {
    private String commander;
    private int soldiers;
    private int guns;
    private int horses;
    private int officers;
    // getters & setters
    public Army(){
    }

    @Override
    public String toString() {
        return "Army{" +
                "commander='" + commander + '\'' +
                ", soldiers=" + soldiers +
                ", guns=" + guns +
                ", horses=" + horses +
                ", officers=" + officers +
                '}';
    }

    public String toString(String type) {
        var result = toString();
        return result.replace("Army", type);
    }
}

This is my child class, where I am using the toString(String type)method from the parent class inside the toString method of the child class:

public class PanzerArmy extends Army {
    private String tanks = "tanks";

    public String getTanks() {
        return tanks;
    }

    public void setTanks(String tanks) {
        this.tanks = tanks;
    }

    @Override
    public String toString() {
        return super.toString("PanzerArmy") +
                " tanks='" + tanks + '\'' +
                '}';
    }
}

When I try to display object of child class I get this error:

Exception in thread "main" java.lang.StackOverflowError


Solution

  • In Your PanzerArmy.toString() you call Army.toString(String), which in turn calls toString(). You might expect Army.toString() to be executed here, but since you overrode it in PanzerArmy (and the current object is of type PanzerArmy) it will call PanzerArmy.toString(). .. which will call Army.toString(String) and start the whole jazz again, in a never ending recursion. Eventually the JDK decides that it's got enough of this and bails.

    A better solution would be to make the toString() in Army abstract and only implement toString(String).

    Alternatively you could use something like getClass().getSimpleName() to get the short name of the current class and immediately use that instead of having to tweak toString() for each subclass.