[{"data":1,"prerenderedAt":114},["ShallowReactive",2],{"qa-\u002Fjava\u002Foop\u002Fpolymorphism":3},{"page":4,"siblings":94,"blog":111},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":19,"order":20,"path":21,"questions":22,"questionsCount":85,"related":86,"seo":87,"seoDescription":88,"stem":89,"subtopic":6,"topic":90,"topicSlug":91,"updated":92,"__hash__":93},"qa\u002Fjava\u002Foop\u002Fpolymorphism.md","Polymorphism",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"medium","md","Java","java",{},true,3,"\u002Fjava\u002Foop\u002Fpolymorphism",[23,27,31,35,39,43,48,52,56,60,64,68,73,77,81],{"id":24,"difficulty":14,"q":25,"a":26},"polymorphism","What is polymorphism and what are its forms?","Polymorphism = \"many forms.\" Java has two kinds:\n\n- **Runtime (dynamic) polymorphism** — method **overriding**. The JVM picks the\n  method based on the *actual object* at runtime (dynamic dispatch).\n- **Compile-time (static) polymorphism** — method **overloading**. The compiler\n  picks the method based on the *declared argument types*.\n\n```java\nAnimal a = new Dog();\na.sound();   \u002F\u002F runtime: Dog's override is chosen\n\nprint(5);    \u002F\u002F compile-time: print(int)\nprint(\"hi\"); \u002F\u002F compile-time: print(String)\n```\n\n\"Polymorphism\" in interviews usually means the runtime kind — the engine behind\n`List\u003CShape>` calling each shape's own `area()`.\n",{"id":28,"difficulty":14,"q":29,"a":30},"overloading-vs-overriding","What is the difference between overloading and overriding?","| | Overloading | Overriding |\n| --- | --- | --- |\n| What | Same name, **different parameters** | Subclass **replaces** a superclass method |\n| Signature | Must differ (type\u002Fcount) | Must be **identical** |\n| Bound | **Compile time** (static) | **Run time** (dynamic) |\n| Return type | Can differ | Same or covariant |\n\n```java\nclass Calc {\n  int add(int a, int b) { return a + b; }          \u002F\u002F overload 1\n  double add(double a, double b) { return a + b; }  \u002F\u002F overload 2\n}\nclass Base { void greet() { } }\nclass Sub extends Base { @Override void greet() { } } \u002F\u002F override\n```\n\nOverloading is about offering variations of an operation; overriding is about\nspecializing inherited behavior. Use `@Override` so the compiler verifies you\nactually overrode (and didn't accidentally overload).\n",{"id":32,"difficulty":14,"q":33,"a":34},"overriding-rules","What are the rules for overriding a method?","To override (not overload), the subclass method must:\n\n1. Have the **same name and parameter list** (signature).\n2. Have the **same or a covariant (narrower)** return type.\n3. Have **the same or wider access** (you can't make it more restrictive).\n4. Throw **the same or fewer\u002Fnarrower** checked exceptions.\n\n```java\nclass Base {\n  protected Number make() throws IOException { return 1; }\n}\nclass Sub extends Base {\n  @Override public Integer make() { return 2; } \u002F\u002F wider access, covariant, no checked throws — OK\n}\n```\n\n`private`, `static`, and `final` methods **can't** be overridden. **Rule of\nthumb:** always add `@Override` — the compiler then rejects anything that's\nsecretly an overload or a typo'd signature.\n",{"id":36,"difficulty":14,"q":37,"a":38},"dynamic-dispatch","What is dynamic method dispatch?","Dynamic (virtual) dispatch is how the JVM decides, **at runtime**, which\noverridden method to call — based on the **actual object's class**, not the\nreference type. It's the mechanism that makes runtime polymorphism work.\n\n```java\nclass Shape { double area() { return 0; } }\nclass Circle extends Shape { double area() { return Math.PI; } }\n\nShape s = new Circle();\ns.area();    \u002F\u002F Circle.area() — chosen by the object, not the Shape reference\n```\n\nEach object carries a pointer to its class's method table (vtable); the call\nlooks up the override there. **Rule of thumb:** instance methods are virtual by\ndefault in Java — the runtime type wins.\n",{"id":40,"difficulty":14,"q":41,"a":42},"runtime-vs-compiletime-poly","How does compile-time polymorphism differ from runtime polymorphism?","- **Compile-time (static) polymorphism** = **overloading**. The compiler resolves\n  the call from the **declared argument types**; fixed before the program runs.\n- **Runtime (dynamic) polymorphism** = **overriding**. The JVM resolves the call\n  from the **actual object** during execution.\n\n```java\nvoid print(int x) { }\nvoid print(Object o) { }\nprint(5);            \u002F\u002F compile-time: print(int) chosen by arg type\n\nAnimal a = pickAnimal();\na.sound();           \u002F\u002F runtime: depends on what pickAnimal() returned\n```\n\n**Rule of thumb:** overloading is decided by *what the compiler sees* (reference\ntypes); overriding by *what actually exists* (object type) at runtime.\n",{"id":44,"difficulty":45,"q":46,"a":47},"static-vs-dynamic-binding","hard","What is the difference between static and dynamic binding?","**Static binding** is resolved by the compiler from the **declared type** —\nused for `static`, `private`, `final`, and overloaded methods, plus fields.\n**Dynamic binding** is resolved at runtime from the **actual object type** —\nused for overridden instance methods (virtual dispatch).\n\n```java\nclass A { static void s() { } void v() { } int f = 1; }\nclass B extends A { static void s() { } @Override void v() { } int f = 2; }\n\nA x = new B();\nx.v();   \u002F\u002F B.v()  — dynamic binding (overridden)\nx.s();   \u002F\u002F A.s()  — static binding (hidden, by declared type)\nx.f;     \u002F\u002F 1      — fields are static-bound, not polymorphic\n```\n\nKey insight: **fields and static methods are *hidden*, not overridden** — they\nbind to the declared type, which is a classic trick question.\n",{"id":49,"difficulty":45,"q":50,"a":51},"method-hiding","What is method hiding and how does it differ from overriding?","When a subclass declares a `static` method with the same signature as a parent\n`static` method, it **hides** rather than overrides it. The version called\ndepends on the **declared (compile-time) type**, not the runtime object — the\nopposite of overriding.\n\n```java\nclass A { static String who() { return \"A\"; } }\nclass B extends A { static String who() { return \"B\"; } }\n\nA ref = new B();\nref.who();   \u002F\u002F \"A\"  — static method, resolved by declared type (hiding)\n\u002F\u002F If who() were an instance method, this would be \"B\" (overriding)\n```\n\nBecause of this confusion, call static methods on the **class** (`A.who()`),\nnever through an instance reference.\n",{"id":53,"difficulty":45,"q":54,"a":55},"covariant-return","What is a covariant return type?","When overriding, the subclass method may return a **subtype** of the\nsuperclass method's return type — a covariant return. It lets overrides return\nmore specific types without a cast.\n\n```java\nclass Animal { Animal reproduce() { return new Animal(); } }\nclass Dog extends Animal {\n  @Override Dog reproduce() { return new Dog(); } \u002F\u002F narrower return — legal\n}\nDog puppy = new Dog().reproduce(); \u002F\u002F no cast needed\n```\n\nCommon in builder patterns and `clone()` overrides. (Parameters, by contrast,\nare *not* covariant — changing a parameter type makes it an overload, not an\noverride.)\n",{"id":57,"difficulty":14,"q":58,"a":59},"can-override-static","Can you override a static, final or private method?","No to all three, for different reasons:\n\n- **`static`** — bound to the class, not the instance; redeclaring it in a\n  subclass **hides** it (resolved by declared type), it isn't overridden.\n- **`final`** — explicitly sealed against overriding; won't compile if you try.\n- **`private`** — not visible to the subclass at all, so a same-named method is a\n  brand-new, unrelated method.\n\n```java\nclass A {\n  static void s() { }\n  final void f() { }\n  private void p() { }\n}\nclass B extends A {\n  static void s() { }    \u002F\u002F hides, not overrides\n  \u002F\u002F void f() { }        \u002F\u002F ERROR — can't override final\n  void p() { }           \u002F\u002F new method — A.p() is invisible here\n}\n```\n\n**Rule of thumb:** only **inherited, visible, non-final instance** methods are\ntruly overridable.\n",{"id":61,"difficulty":45,"q":62,"a":63},"overload-resolution","How does the compiler resolve which overload to call?","The compiler picks the **most specific** applicable overload using the\n**compile-time (declared) argument types**, in phases: exact\u002Fwidening match\nfirst, then autoboxing, then varargs — preferring the path that needs the least\nconversion.\n\n```java\nvoid m(Object o) { }\nvoid m(Integer i) { }\nvoid m(int... xs) { }\n\nm(5);          \u002F\u002F m(int...)? No — m(Integer) via boxing beats varargs?\n               \u002F\u002F Actually: widening\u002Fboxing phase -> m(Integer) chosen over varargs\nInteger n = null;\nm(n);          \u002F\u002F m(Integer) — reference match, no boxing\n```\n\nBecause it uses **static types**, `m((Object) myInteger)` calls `m(Object)` even\nif the value is an `Integer`. **Rule of thumb:** overloads are resolved by the\n*reference type you pass*, not the runtime value — avoid ambiguous overloads.\n",{"id":65,"difficulty":14,"q":66,"a":67},"polymorphism-collections","How does polymorphism enable programming to an interface?","By declaring variables and parameters as the **interface\u002Fsupertype**, your code\nworks with *any* implementation — the runtime calls the actual object's\nmethods. This decouples callers from concrete classes.\n\n```java\nvoid process(List\u003CString> items) { }   \u002F\u002F accepts ArrayList, LinkedList, List.of...\nList\u003CString> list = new ArrayList\u003C>();  \u002F\u002F swap impl freely\n\u002F\u002F list = new LinkedList\u003C>();           \u002F\u002F no caller changes needed\n```\n\n\"Program to an interface, not an implementation\" — depend on `List`, `Map`,\n`Collection`, not `ArrayList`\u002F`HashMap`. It makes code testable (inject fakes)\nand flexible (change implementations without ripple effects).\n",{"id":69,"difficulty":70,"q":71,"a":72},"super-in-override","easy","How do you call the parent's version of an overridden method?","Use `super.method()`. Inside an override, `super` skips the current class's\nversion and invokes the **immediate superclass's** implementation — useful to\n*extend* rather than *replace* behavior.\n\n```java\nclass Logger { void log(String m) { System.out.println(m); } }\nclass TimestampLogger extends Logger {\n  @Override void log(String m) {\n    super.log(java.time.Instant.now() + \" \" + m);  \u002F\u002F reuse + augment\n  }\n}\n```\n\nYou can only reach **one level up** — there's no `super.super`. **Rule of thumb:**\n`super.method()` is the \"decorate the inherited behavior\" tool.\n",{"id":74,"difficulty":14,"q":75,"a":76},"abstract-polymorphism","How do abstract methods support polymorphism?","An **abstract method** declares a contract with no body; each concrete subclass\n*must* provide an implementation. Code calling the method through the abstract\ntype gets each subclass's behavior via dynamic dispatch — polymorphism with a\ncompiler-enforced contract.\n\n```java\nabstract class Shape { abstract double area(); }\nclass Circle extends Shape { double area() { return Math.PI * r * r; } double r = 1; }\nclass Square extends Shape { double area() { return s * s; } double s = 2; }\n\nfor (Shape sh : List.of(new Circle(), new Square()))\n  sh.area();   \u002F\u002F each computes its own — caller doesn't care which\n```\n\n**Rule of thumb:** abstract methods are \"polymorphism you can't forget to\nimplement\" — the compiler stops you from leaving a hole.\n",{"id":78,"difficulty":14,"q":79,"a":80},"why-override-equals-poly","Why is calling an overridable method from a constructor dangerous?","During construction the **subclass override runs before the subclass's fields are\ninitialized**, because the superclass constructor executes first. The override\nthen sees default (`null`\u002F`0`) values.\n\n```java\nclass Base {\n  Base() { init(); }            \u002F\u002F calls the override...\n  void init() { }\n}\nclass Sub extends Base {\n  String name = \"set\";\n  @Override void init() { System.out.println(name); } \u002F\u002F prints null!\n}\nnew Sub();   \u002F\u002F null — name not assigned yet\n```\n\nThis is dynamic dispatch biting you mid-construction. **Rule of thumb:** never\ncall overridable (non-`final`, non-`private`) methods from a constructor — make\nsuch helpers `final` or `private`.\n",{"id":82,"difficulty":70,"q":83,"a":84},"polymorphism-benefits","What practical benefits does polymorphism give you?","- **Extensibility** — add a new subtype without touching code that uses the\n  supertype (open\u002Fclosed principle).\n- **Decoupling** — callers depend on an abstraction, so implementations swap\n  freely (and fakes\u002Fmocks slot in for tests).\n- **Cleaner code** — replaces `if\u002Felse`\u002F`switch` on type with one virtual call.\n\n```java\n\u002F\u002F No type-switching — each shape knows its own area\ndouble total = 0;\nfor (Shape s : shapes) total += s.area();\n```\n\n**Rule of thumb:** when you see a `switch` on an object's \"kind,\" polymorphism\nusually expresses it better — give each kind its own method.\n",15,null,{"description":11},"Java polymorphism interview questions — overloading vs overriding, runtime vs compile-time polymorphism, dynamic dispatch, overriding rules, covariant returns, method hiding, static\u002Fdynamic binding and programming to an interface.","java\u002Foop\u002Fpolymorphism","Object-Oriented Programming","oop","2026-06-19","7o2uqyC5UrgJanCk1Qm7O3uwi92NkXboNuX1-MmHgdE",[95,99,102,103,107],{"subtopic":96,"path":97,"order":98},"Classes & Objects","\u002Fjava\u002Foop\u002Fclasses-objects",1,{"subtopic":100,"path":101,"order":12},"Inheritance","\u002Fjava\u002Foop\u002Finheritance",{"subtopic":6,"path":21,"order":20},{"subtopic":104,"path":105,"order":106},"Interfaces vs Abstract Classes","\u002Fjava\u002Foop\u002Finterfaces-vs-abstract",4,{"subtopic":108,"path":109,"order":110},"equals & hashCode","\u002Fjava\u002Foop\u002Fequals-hashcode",5,{"path":112,"title":113},"\u002Fblog\u002Fjava-polymorphism-overriding-overloading","Java Polymorphism Explained — Overriding vs Overloading & Dynamic Dispatch",1782244115444]