Java Tutorial

Java Polymorphism

A superclass variable can hold a subclass object. When you call an overridden method, the version that runs is the object's real type — not the variable's declared type.

One variable, many shapes

Polymorphism ("many forms") lets you write code against a general type while the runtime picks the specific behavior. Declare Animal a = new Dog(); and a.speak() still prints woof.

Example

class Animal {
  void speak() {
    System.out.println("...");
  }
}

class Dog extends Animal {
  @Override
  void speak() {
    System.out.println("woof");
  }
}

class Cat extends Animal {
  @Override
  void speak() {
    System.out.println("meow");
  }
}

public class Main {
  public static void main(String[] args) {
    Animal a = new Dog();
    a.speak();              // woof
    a = new Cat();
    a.speak();              // meow
  }
}

Collections of a base type

The payoff is treating different subclasses the same way in a loop. You store Animal references and call one method; each object answers in its own way.

Example

class Animal {
  void speak() { System.out.println("..."); }
}
class Dog extends Animal {
  @Override void speak() { System.out.println("woof"); }
}
class Cat extends Animal {
  @Override void speak() { System.out.println("meow"); }
}

public class Main {
  public static void main(String[] args) {
    Animal[] zoo = { new Dog(), new Cat(), new Dog() };
    for (Animal a : zoo) {
      a.speak();
    }
  }
}

Override vs overload

Overriding replaces a superclass method with the same signature; the JVM chooses it at runtime. Overloading is several methods with the same name but different parameters; the compiler chooses at compile time. Do not mix the terms.

Example — helper that takes Animal

class Animal {
  void speak() { System.out.println("..."); }
}
class Dog extends Animal {
  @Override void speak() { System.out.println("woof"); }
}

public class Main {
  static void chorus(Animal a) {
    a.speak();   // dynamic: depends on the real object
  }

  public static void main(String[] args) {
    chorus(new Dog());
    chorus(new Animal());
  }
}

The variable's type decides which methods you may call. The object's type decides which overrideruns. If only Dog has fetch(), an Animal variable cannot call it without a cast.

Try It Yourself

Exercise: Add a Bird subclass that prints "chirp". Put aDog, Cat, and Bird in an Animal[] and callspeak on each.

Show solution
class Animal {
  void speak() { System.out.println("..."); }
}
class Dog extends Animal {
  @Override void speak() { System.out.println("woof"); }
}
class Cat extends Animal {
  @Override void speak() { System.out.println("meow"); }
}
class Bird extends Animal {
  @Override void speak() { System.out.println("chirp"); }
}

public class Main {
  public static void main(String[] args) {
    Animal[] zoo = { new Dog(), new Cat(), new Bird() };
    for (Animal a : zoo) a.speak();
  }
}

One loop, three behaviors — that is polymorphism in a sentence.

Key Takeaways

  • A superclass reference can point at a subclass object.
  • Overridden methods run based on the object's real type (runtime).
  • Polymorphism lets you write loops and helpers against a general type.
  • Overriding is not overloading — different times, different rules.

Worked examples

The short listings above are there so you can see the grammar. The programs here use the same statements on quantities that already have units: a speed, a pH, a count of bases. They are classroom numbers. Air resistance is ignored. g is 9.81 m/s² unless a line says otherwise.

Open them in the Java editor at /java/try. Change one measurement and check whether the result still has the right unit.

Maths

Same call, different area

A Shape reference can hold a Square or a Circle. area() dispatches to the runtime type.

A = s² or A = πr²

Example

abstract class Shape {
  abstract double area();
}
class Square extends Shape {
  double s;
  Square(double s) { this.s = s; }
  double area() { return s * s; }
}
class Circle extends Shape {
  double r;
  Circle(double r) { this.r = r; }
  double area() { return Math.PI * r * r; }
}

public class Main {
  public static void main(String[] args) {
    Shape p = new Circle(1.0);
    System.out.println(p.area());
  }
}

FAQ: Java Polymorphism

Common questions about this page.

What is the StudyGrid Java tutorial?

The StudyGrid Java tutorial is a full beginner-to-advanced track: syntax, types, input, loops, methods, classes, collections, generics, maps, and lambdas. Each chapter has copy-and-run examples.

Should I run java polymorphism examples locally for better learning?

Yes. Use the browser editor on StudyGrid for a quick check, then Download the example and run it on your computer. Local runs show real errors and the real toolchain, which is one of the fastest ways to learn java polymorphism in this Java Java lesson (Java Polymorphism).

Is the Java editor the same as Try Python or Try C++?

No. Try Java compiles with javac at /java/try and shows stdout plus compiler messages. Try Python stays at /try. Try C++ stays at /cpp/try. Java lessons never open those editors.

Do I need to install a JDK to learn Java?

No. Open a chapter, click Try it in Java, and compile in the browser. You can also download a .java file and compile locally with javac.

Where should I start the Java tutorial?

Start at Java Intro, then Get Started and Syntax. After the first program, continue to output, variables, and if-else. After classes, open Java Examples, then generics, map, and lambdas. Use Next at the bottom of each chapter.

Is the Java tutorial free?

Yes. The Java workshop on StudyGrid (studygrid.in) is free: dashboard, chapters, and the compile-and-run editor.