Understanding Polymorphism in Java: Concepts, Implementation, and Classic Examples
This article explains the three core object‑oriented concepts, focuses on runtime polymorphism in Java, describes its required conditions, demonstrates implementation through inheritance and interfaces with detailed code examples, and analyzes classic method‑overloading scenarios.
Polymorphism in Java
Object‑oriented programming (OOP) is built on three fundamental features: encapsulation, inheritance, and polymorphism. Encapsulation hides internal implementation, inheritance enables code reuse, and polymorphism allows a reference to invoke different method implementations at runtime.
Polymorphism means that the actual method executed is determined during program execution based on the concrete object type that a reference points to. This enables the same code to work with objects of different subclasses without modification.
Key Concepts
Upcasting (assigning a subclass object to a superclass reference) is required for polymorphic behavior.
When a superclass reference calls a method, the JVM selects the overridden method in the actual subclass.
Methods not declared in the superclass cannot be accessed through the superclass reference, even if they exist in the subclass.
Implementation Conditions in Java
To achieve runtime polymorphism in Java, three conditions must be met:
Inheritance relationship between classes.
Method overriding in the subclass.
Upcasting of the subclass instance to a superclass type.
Implementation via Inheritance
The following code demonstrates inheritance‑based polymorphism with a base class Wine and subclasses JNC and JGJ that override drink() and toString() :
public class Wine {
private String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String drink() { return "喝的是 " + getName(); }
public String toString() { return null; }
}
public class JNC extends Wine {
public JNC() { setName("JNC"); }
@Override
public String drink() { return "喝的是 " + getName(); }
@Override
public String toString() { return "Wine : " + getName(); }
}
public class JGJ extends Wine {
public JGJ() { setName("JGJ"); }
@Override
public String drink() { return "喝的是 " + getName(); }
@Override
public String toString() { return "Wine : " + getName(); }
}
public class Test {
public static void main(String[] args) {
Wine[] wines = new Wine[2];
wines[0] = new JNC();
wines[1] = new JGJ();
for (int i = 0; i < 2; i++) {
System.out.println(wines[i].toString() + "--" + wines[i].drink());
}
}
}Running this program prints the subclass implementations, confirming that the overridden methods are invoked.
Implementation via Interfaces
Polymorphism can also be achieved through interfaces, allowing a reference of the interface type to point to any implementing class. This provides greater flexibility because a class can implement multiple interfaces.
Classic Example – Method Overloading and Overriding
The article presents a classic example with classes A , B , C , and D to illustrate how the compiler selects methods based on the reference type and the actual object type:
public class A {
public String show(D obj) { return "A and D"; }
public String show(A obj) { return "A and A"; }
}
public class B extends A {
public String show(B obj) { return "B and B"; }
@Override
public String show(A obj) { return "B and A"; }
}
public class C extends B {}
public class D extends B {}
public class Test {
public static void main(String[] args) {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println("1--" + a1.show(b));
System.out.println("2--" + a1.show(c));
System.out.println("3--" + a1.show(d));
System.out.println("4--" + a2.show(b));
System.out.println("5--" + a2.show(c));
System.out.println("6--" + a2.show(d));
System.out.println("7--" + b.show(b));
System.out.println("8--" + b.show(c));
System.out.println("9--" + b.show(d));
}
}The output demonstrates how the JVM resolves method calls, emphasizing that only methods declared in the superclass can be invoked polymorphically, even when the subclass defines overloaded versions.
In summary, Java polymorphism relies on inheritance, method overriding, and upcasting, and can be realized through both class inheritance and interface implementation, enabling flexible and reusable code.
Java Captain
Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.