Did you know you’re already using inheritance in every Java class you write? In Java, all classes implicitly inherit from a superclass called Object if they don’t explicitly extend another class. This means every class you create automatically receives methods like toString(), equals(), and hashCode().
Since every class in Java implicitly extends the Object class (either directly or indirectly), any instance of any class can be assigned to a reference of type Object. This means that Java enables polymorphic handling by allowing variables of type Object to store references to any Java object, regardless of its actual class.
public class Player {
private String name;
private int health;
public Player(String name, int health) {
this.name = name;
this.health = health;
}
// No toString() override
}
// Later in code
Player hero = new Player("Hero", 100);
System.out.println(hero); // Outputs something like: Player@7a81197d
The output is not very readable because we’re using the default toString() implementation inherited from Object. This default is deliberately minimal. Java can’t assume what information would be meaningful for every possible class, so it provides a basic implementation that you’re expected to override with class-specific behavior.
This example illustrates an important inheritance concept: while inheriting methods is convenient, sometimes the parent class’s implementation doesn’t fit the specific needs of the subclass which is a perfect scenario for method overriding, which we’ll explore in the next chapter.