[{"data":1,"prerenderedAt":1373},["ShallowReactive",2],{"blog-\u002Fblog\u002Fjava-polymorphism-overriding-overloading":3},{"id":4,"title":5,"body":6,"description":1360,"difficulty":1361,"extension":1362,"framework":1363,"frameworkSlug":45,"meta":1364,"navigation":93,"order":90,"path":1365,"qaPath":1366,"seo":1367,"stem":1368,"subtopic":20,"topic":1369,"topicSlug":1370,"updated":1371,"__hash__":1372},"blog\u002Fblog\u002Fjava-polymorphism-overriding-overloading.md","Java Polymorphism Explained — Overriding vs Overloading & Dynamic Dispatch",{"type":7,"value":8,"toc":1348},"minimark",[9,14,40,131,135,142,173,245,252,256,262,297,408,417,421,439,472,561,579,583,600,690,709,713,724,820,842,846,869,1021,1043,1047,1075,1151,1167,1171,1190,1283,1297,1301,1344],[10,11,13],"h2",{"id":12},"polymorphism-one-reference-many-forms","Polymorphism: one reference, many forms",[15,16,17,21,22,26,27,30,31,35,36,39],"p",{},[18,19,20],"strong",{},"Polymorphism"," means \"many forms\" — a single reference type that behaves differently\ndepending on the actual object behind it. It is the mechanism that lets a ",[23,24,25],"code",{},"List\u003CShape>","\ncall each shape's own ",[23,28,29],{},"area()"," without the caller knowing or caring which concrete class\nit holds. Interviewers probe polymorphism because it separates people who ",[32,33,34],"em",{},"recite"," \"the\nfour pillars\" from people who understand ",[32,37,38],{},"how dispatch actually happens"," — and because the\nedge cases (hidden statics, covariant returns, overload resolution) are where real bugs\nlive. Java gives you two distinct flavors, decided at two different times.",[41,42,47],"pre",{"className":43,"code":44,"language":45,"meta":46,"style":46},"language-java shiki shiki-themes github-light github-dark","Animal a = new Dog();\na.sound();        \u002F\u002F runtime form: Dog's override is chosen by the object\n\nprint(5);         \u002F\u002F compile-time form: print(int) chosen by the argument type\nprint(\"hi\");      \u002F\u002F compile-time form: print(String)\n","java","",[23,48,49,72,88,95,114],{"__ignoreMap":46},[50,51,54,58,62,65,69],"span",{"class":52,"line":53},"line",1,[50,55,57],{"class":56},"sVt8B","Animal a ",[50,59,61],{"class":60},"szBVR","=",[50,63,64],{"class":60}," new",[50,66,68],{"class":67},"sScJk"," Dog",[50,70,71],{"class":56},"();\n",[50,73,75,78,81,84],{"class":52,"line":74},2,[50,76,77],{"class":56},"a.",[50,79,80],{"class":67},"sound",[50,82,83],{"class":56},"();        ",[50,85,87],{"class":86},"sJ8bj","\u002F\u002F runtime form: Dog's override is chosen by the object\n",[50,89,91],{"class":52,"line":90},3,[50,92,94],{"emptyLinePlaceholder":93},true,"\n",[50,96,98,101,104,108,111],{"class":52,"line":97},4,[50,99,100],{"class":67},"print",[50,102,103],{"class":56},"(",[50,105,107],{"class":106},"sj4cs","5",[50,109,110],{"class":56},");         ",[50,112,113],{"class":86},"\u002F\u002F compile-time form: print(int) chosen by the argument type\n",[50,115,117,119,121,125,128],{"class":52,"line":116},5,[50,118,100],{"class":67},[50,120,103],{"class":56},[50,122,124],{"class":123},"sZZnC","\"hi\"",[50,126,127],{"class":56},");      ",[50,129,130],{"class":86},"\u002F\u002F compile-time form: print(String)\n",[10,132,134],{"id":133},"runtime-vs-compile-time-polymorphism","Runtime vs compile-time polymorphism",[15,136,137,138,141],{},"The two flavors differ in ",[32,139,140],{},"when the call is resolved",":",[143,144,145,160],"ul",{},[146,147,148,151,152,155,156,159],"li",{},[18,149,150],{},"Runtime (dynamic) polymorphism"," is ",[18,153,154],{},"method overriding",". The JVM picks the method\nfrom the ",[18,157,158],{},"actual object's class"," during execution.",[146,161,162,151,165,168,169,172],{},[18,163,164],{},"Compile-time (static) polymorphism",[18,166,167],{},"method overloading",". The compiler picks the\nmethod from the ",[18,170,171],{},"declared argument types",", fixed before the program runs.",[41,174,176],{"className":43,"code":175,"language":45,"meta":46,"style":46},"void print(int x) { }\nvoid print(Object o) { }\nprint(5);              \u002F\u002F compile-time: print(int) — chosen by the literal's type\n\nAnimal a = pickAnimal();\na.sound();             \u002F\u002F runtime: depends on what pickAnimal() actually returned\n",[23,177,178,194,203,217,221,232],{"__ignoreMap":46},[50,179,180,183,186,188,191],{"class":52,"line":53},[50,181,182],{"class":60},"void",[50,184,185],{"class":67}," print",[50,187,103],{"class":56},[50,189,190],{"class":60},"int",[50,192,193],{"class":56}," x) { }\n",[50,195,196,198,200],{"class":52,"line":74},[50,197,182],{"class":60},[50,199,185],{"class":67},[50,201,202],{"class":56},"(Object o) { }\n",[50,204,205,207,209,211,214],{"class":52,"line":90},[50,206,100],{"class":67},[50,208,103],{"class":56},[50,210,107],{"class":106},[50,212,213],{"class":56},");              ",[50,215,216],{"class":86},"\u002F\u002F compile-time: print(int) — chosen by the literal's type\n",[50,218,219],{"class":52,"line":97},[50,220,94],{"emptyLinePlaceholder":93},[50,222,223,225,227,230],{"class":52,"line":116},[50,224,57],{"class":56},[50,226,61],{"class":60},[50,228,229],{"class":67}," pickAnimal",[50,231,71],{"class":56},[50,233,235,237,239,242],{"class":52,"line":234},6,[50,236,77],{"class":56},[50,238,80],{"class":67},[50,240,241],{"class":56},"();             ",[50,243,244],{"class":86},"\u002F\u002F runtime: depends on what pickAnimal() actually returned\n",[15,246,247,248,251],{},"When an interviewer says \"polymorphism\" with no qualifier, they almost always mean the\n",[18,249,250],{},"runtime"," kind — overriding plus dynamic dispatch. Overloading is the lesser cousin;\nit's really just a naming convenience the compiler resolves statically.",[10,253,255],{"id":254},"method-overriding-and-its-rules","Method overriding and its rules",[15,257,258,261],{},[18,259,260],{},"Overriding"," is when a subclass replaces an inherited instance method with its own\nimplementation. To genuinely override (and not accidentally overload), the subclass method\nmust obey four rules:",[263,264,265,271,277,291],"ol",{},[146,266,267,270],{},[18,268,269],{},"Same name and parameter list"," — the signature must be identical.",[146,272,273,276],{},[18,274,275],{},"Same or covariant return type"," — you may narrow it to a subtype, never widen it.",[146,278,279,282,283,286,287,290],{},[18,280,281],{},"Same or wider access"," — you can loosen ",[23,284,285],{},"protected"," to ",[23,288,289],{},"public",", never tighten it.",[146,292,293,296],{},[18,294,295],{},"Same or fewer\u002Fnarrower checked exceptions"," — you can throw less, never more.",[41,298,300],{"className":43,"code":299,"language":45,"meta":46,"style":46},"class Base {\n  protected Number make() throws IOException { return 1; }\n}\nclass Sub extends Base {\n  @Override public Integer make() {     \u002F\u002F wider access, covariant return,\n    return 2;                            \u002F\u002F and no checked throws — all legal\n  }\n}\n",[23,301,302,313,342,347,361,383,397,403],{"__ignoreMap":46},[50,303,304,307,310],{"class":52,"line":53},[50,305,306],{"class":60},"class",[50,308,309],{"class":67}," Base",[50,311,312],{"class":56}," {\n",[50,314,315,318,321,324,327,330,333,336,339],{"class":52,"line":74},[50,316,317],{"class":60},"  protected",[50,319,320],{"class":56}," Number ",[50,322,323],{"class":67},"make",[50,325,326],{"class":56},"() ",[50,328,329],{"class":60},"throws",[50,331,332],{"class":56}," IOException { ",[50,334,335],{"class":60},"return",[50,337,338],{"class":106}," 1",[50,340,341],{"class":56},"; }\n",[50,343,344],{"class":52,"line":90},[50,345,346],{"class":56},"}\n",[50,348,349,351,354,357,359],{"class":52,"line":97},[50,350,306],{"class":60},[50,352,353],{"class":67}," Sub",[50,355,356],{"class":60}," extends",[50,358,309],{"class":67},[50,360,312],{"class":56},[50,362,363,366,369,372,375,377,380],{"class":52,"line":116},[50,364,365],{"class":56},"  @",[50,367,368],{"class":60},"Override",[50,370,371],{"class":60}," public",[50,373,374],{"class":56}," Integer ",[50,376,323],{"class":67},[50,378,379],{"class":56},"() {     ",[50,381,382],{"class":86},"\u002F\u002F wider access, covariant return,\n",[50,384,385,388,391,394],{"class":52,"line":234},[50,386,387],{"class":60},"    return",[50,389,390],{"class":106}," 2",[50,392,393],{"class":56},";                            ",[50,395,396],{"class":86},"\u002F\u002F and no checked throws — all legal\n",[50,398,400],{"class":52,"line":399},7,[50,401,402],{"class":56},"  }\n",[50,404,406],{"class":52,"line":405},8,[50,407,346],{"class":56},[15,409,410,411,416],{},"Always write ",[18,412,413],{},[23,414,415],{},"@Override",". It costs nothing and turns a silent mistake — a typo'd\nsignature that quietly becomes a brand-new overload — into a compile error. The annotation\nis the single cheapest correctness tool in the language.",[10,418,420],{"id":419},"method-overloading-and-how-the-compiler-resolves-it","Method overloading and how the compiler resolves it",[15,422,423,426,427,430,431,434,435,438],{},[18,424,425],{},"Overloading"," offers several methods with the ",[18,428,429],{},"same name but different parameters",".\nResolution is the compiler's job, and it follows a strict phased search for the ",[18,432,433],{},"most\nspecific"," applicable candidate using the ",[18,436,437],{},"static (declared) types"," of the arguments:",[263,440,441,455,466],{},[146,442,443,444,447,448,450,451,454],{},"Exact match and ",[18,445,446],{},"widening"," primitive conversions (",[23,449,190],{}," → ",[23,452,453],{},"long",").",[146,456,457,460,461,450,463,454],{},[18,458,459],{},"Autoboxing\u002Funboxing"," (",[23,462,190],{},[23,464,465],{},"Integer",[146,467,468,471],{},[18,469,470],{},"Varargs",".",[41,473,475],{"className":43,"code":474,"language":45,"meta":46,"style":46},"void m(Object o)   { }\nvoid m(Integer i)  { }\nvoid m(int... xs)  { }\n\nm(5);                 \u002F\u002F m(Integer) wins via boxing — preferred over varargs\nInteger n = null;\nm(n);                 \u002F\u002F m(Integer) — direct reference match, no boxing\nm((Object) n);        \u002F\u002F m(Object) — the *cast* changes the static type\n",[23,476,477,487,496,509,513,528,541,551],{"__ignoreMap":46},[50,478,479,481,484],{"class":52,"line":53},[50,480,182],{"class":60},[50,482,483],{"class":67}," m",[50,485,486],{"class":56},"(Object o)   { }\n",[50,488,489,491,493],{"class":52,"line":74},[50,490,182],{"class":60},[50,492,483],{"class":67},[50,494,495],{"class":56},"(Integer i)  { }\n",[50,497,498,500,502,504,506],{"class":52,"line":90},[50,499,182],{"class":60},[50,501,483],{"class":67},[50,503,103],{"class":56},[50,505,190],{"class":60},[50,507,508],{"class":56},"... xs)  { }\n",[50,510,511],{"class":52,"line":97},[50,512,94],{"emptyLinePlaceholder":93},[50,514,515,518,520,522,525],{"class":52,"line":116},[50,516,517],{"class":67},"m",[50,519,103],{"class":56},[50,521,107],{"class":106},[50,523,524],{"class":56},");                 ",[50,526,527],{"class":86},"\u002F\u002F m(Integer) wins via boxing — preferred over varargs\n",[50,529,530,533,535,538],{"class":52,"line":234},[50,531,532],{"class":56},"Integer n ",[50,534,61],{"class":60},[50,536,537],{"class":106}," null",[50,539,540],{"class":56},";\n",[50,542,543,545,548],{"class":52,"line":399},[50,544,517],{"class":67},[50,546,547],{"class":56},"(n);                 ",[50,549,550],{"class":86},"\u002F\u002F m(Integer) — direct reference match, no boxing\n",[50,552,553,555,558],{"class":52,"line":405},[50,554,517],{"class":67},[50,556,557],{"class":56},"((Object) n);        ",[50,559,560],{"class":86},"\u002F\u002F m(Object) — the *cast* changes the static type\n",[15,562,563,564,567,568,571,572,575,576,578],{},"The decisive insight: overloads are chosen by ",[18,565,566],{},"the reference type you pass, not the\nruntime value",". ",[23,569,570],{},"m((Object) myInteger)"," calls ",[23,573,574],{},"m(Object)"," even though the object is an\n",[23,577,465],{},". Ambiguous or near-overlapping overloads breed subtle bugs — when in doubt, give\nthe methods distinct names.",[10,580,582],{"id":581},"dynamic-dispatch-the-engine-of-overriding","Dynamic dispatch: the engine of overriding",[15,584,585,588,589,592,593,595,596,599],{},[18,586,587],{},"Dynamic (virtual) method dispatch"," is how the JVM decides ",[32,590,591],{},"at runtime"," which overridden\nmethod to invoke — based on the ",[18,594,158],{},", never the reference type. Every\nobject carries a pointer to its class's method table (a ",[18,597,598],{},"vtable","); a virtual call looks\nup the override there.",[41,601,603],{"className":43,"code":602,"language":45,"meta":46,"style":46},"class Shape  { double area() { return 0; } }\nclass Circle extends Shape { @Override double area() { return Math.PI; } }\n\nShape s = new Circle();\ns.area();             \u002F\u002F Circle.area() — the object decides, not the Shape reference\n",[23,604,605,632,660,664,677],{"__ignoreMap":46},[50,606,607,609,612,615,618,621,624,626,629],{"class":52,"line":53},[50,608,306],{"class":60},[50,610,611],{"class":67}," Shape",[50,613,614],{"class":56},"  { ",[50,616,617],{"class":60},"double",[50,619,620],{"class":67}," area",[50,622,623],{"class":56},"() { ",[50,625,335],{"class":60},[50,627,628],{"class":106}," 0",[50,630,631],{"class":56},"; } }\n",[50,633,634,636,639,641,643,646,648,651,653,655,657],{"class":52,"line":74},[50,635,306],{"class":60},[50,637,638],{"class":67}," Circle",[50,640,356],{"class":60},[50,642,611],{"class":67},[50,644,645],{"class":56}," { @",[50,647,368],{"class":60},[50,649,650],{"class":60}," double",[50,652,620],{"class":67},[50,654,623],{"class":56},[50,656,335],{"class":60},[50,658,659],{"class":56}," Math.PI; } }\n",[50,661,662],{"class":52,"line":90},[50,663,94],{"emptyLinePlaceholder":93},[50,665,666,669,671,673,675],{"class":52,"line":97},[50,667,668],{"class":56},"Shape s ",[50,670,61],{"class":60},[50,672,64],{"class":60},[50,674,638],{"class":67},[50,676,71],{"class":56},[50,678,679,682,685,687],{"class":52,"line":116},[50,680,681],{"class":56},"s.",[50,683,684],{"class":67},"area",[50,686,241],{"class":56},[50,688,689],{"class":86},"\u002F\u002F Circle.area() — the object decides, not the Shape reference\n",[15,691,692,693,696,697,700,701,704,705,708],{},"In Java, ",[18,694,695],{},"instance methods are virtual by default"," — there is no ",[23,698,699],{},"virtual"," keyword\nbecause everything non-static, non-final, non-private already is. The runtime type always\nwins. This is precisely why a ",[23,702,703],{},"for (Shape sh : shapes) total += sh.area();"," loop computes\nthe right area for every concrete shape without a single ",[23,706,707],{},"instanceof"," check.",[10,710,712],{"id":711},"covariant-return-types","Covariant return types",[15,714,715,716,719,720,723],{},"When you override, the subclass may return a ",[18,717,718],{},"subtype"," of the original return type. This\n",[18,721,722],{},"covariant return"," lets specialized classes hand back specialized objects without forcing\ncallers to cast.",[41,725,727],{"className":43,"code":726,"language":45,"meta":46,"style":46},"class Animal { Animal reproduce() { return new Animal(); } }\nclass Dog extends Animal {\n  @Override Dog reproduce() { return new Dog(); }   \u002F\u002F narrower return — legal\n}\n\nDog puppy = new Dog().reproduce();   \u002F\u002F no cast needed — return type is already Dog\n",[23,728,729,753,765,790,794,798],{"__ignoreMap":46},[50,730,731,733,736,739,742,744,746,748,750],{"class":52,"line":53},[50,732,306],{"class":60},[50,734,735],{"class":67}," Animal",[50,737,738],{"class":56}," { Animal ",[50,740,741],{"class":67},"reproduce",[50,743,623],{"class":56},[50,745,335],{"class":60},[50,747,64],{"class":60},[50,749,735],{"class":67},[50,751,752],{"class":56},"(); } }\n",[50,754,755,757,759,761,763],{"class":52,"line":74},[50,756,306],{"class":60},[50,758,68],{"class":67},[50,760,356],{"class":60},[50,762,735],{"class":67},[50,764,312],{"class":56},[50,766,767,769,771,774,776,778,780,782,784,787],{"class":52,"line":90},[50,768,365],{"class":56},[50,770,368],{"class":60},[50,772,773],{"class":56}," Dog ",[50,775,741],{"class":67},[50,777,623],{"class":56},[50,779,335],{"class":60},[50,781,64],{"class":60},[50,783,68],{"class":67},[50,785,786],{"class":56},"(); }   ",[50,788,789],{"class":86},"\u002F\u002F narrower return — legal\n",[50,791,792],{"class":52,"line":97},[50,793,346],{"class":56},[50,795,796],{"class":52,"line":116},[50,797,94],{"emptyLinePlaceholder":93},[50,799,800,803,805,807,809,812,814,817],{"class":52,"line":234},[50,801,802],{"class":56},"Dog puppy ",[50,804,61],{"class":60},[50,806,64],{"class":60},[50,808,68],{"class":67},[50,810,811],{"class":56},"().",[50,813,741],{"class":67},[50,815,816],{"class":56},"();   ",[50,818,819],{"class":86},"\u002F\u002F no cast needed — return type is already Dog\n",[15,821,822,823,826,827,830,831,834,835,838,839,841],{},"Covariant returns are the backbone of fluent ",[18,824,825],{},"builder patterns"," and well-typed ",[23,828,829],{},"clone()","\noverrides. Note the asymmetry: ",[18,832,833],{},"parameters are not covariant",". Change a parameter type\nand you have written an ",[32,836,837],{},"overload",", not an override — which is exactly the mistake\n",[23,840,415],{}," is there to catch.",[10,843,845],{"id":844},"why-fields-and-static-methods-are-hidden-not-overridden","Why fields and static methods are hidden, not overridden",[15,847,848,849,852,853,856,857,860,861,864,865,868],{},"This is the classic trick question. ",[18,850,851],{},"Overriding applies only to instance methods."," Fields\nand ",[23,854,855],{},"static"," methods are resolved by ",[18,858,859],{},"static binding"," — the compiler picks them from the\n",[18,862,863],{},"declared type"," of the reference. Redeclaring them in a subclass ",[18,866,867],{},"hides"," the parent\nversion rather than overriding it.",[41,870,872],{"className":43,"code":871,"language":45,"meta":46,"style":46},"class A { static String who() { return \"A\"; } int f = 1; void v() { } }\nclass B extends A { static String who() { return \"B\"; } int f = 2; @Override void v() { } }\n\nA x = new B();\nx.v();       \u002F\u002F \"B\" via the override — dynamic binding (instance method)\nx.who();     \u002F\u002F \"A\" — static method resolved by declared type A (hiding)\nx.f;         \u002F\u002F 1   — fields are not polymorphic; declared type A wins\n",[23,873,874,922,970,974,987,1001,1013],{"__ignoreMap":46},[50,875,876,878,881,884,886,889,892,894,896,899,902,904,907,909,911,914,916,919],{"class":52,"line":53},[50,877,306],{"class":60},[50,879,880],{"class":67}," A",[50,882,883],{"class":56}," { ",[50,885,855],{"class":60},[50,887,888],{"class":56}," String ",[50,890,891],{"class":67},"who",[50,893,623],{"class":56},[50,895,335],{"class":60},[50,897,898],{"class":123}," \"A\"",[50,900,901],{"class":56},"; } ",[50,903,190],{"class":60},[50,905,906],{"class":56}," f ",[50,908,61],{"class":60},[50,910,338],{"class":106},[50,912,913],{"class":56},"; ",[50,915,182],{"class":60},[50,917,918],{"class":67}," v",[50,920,921],{"class":56},"() { } }\n",[50,923,924,926,929,931,933,935,937,939,941,943,945,948,950,952,954,956,958,961,963,966,968],{"class":52,"line":74},[50,925,306],{"class":60},[50,927,928],{"class":67}," B",[50,930,356],{"class":60},[50,932,880],{"class":67},[50,934,883],{"class":56},[50,936,855],{"class":60},[50,938,888],{"class":56},[50,940,891],{"class":67},[50,942,623],{"class":56},[50,944,335],{"class":60},[50,946,947],{"class":123}," \"B\"",[50,949,901],{"class":56},[50,951,190],{"class":60},[50,953,906],{"class":56},[50,955,61],{"class":60},[50,957,390],{"class":106},[50,959,960],{"class":56},"; @",[50,962,368],{"class":60},[50,964,965],{"class":60}," void",[50,967,918],{"class":67},[50,969,921],{"class":56},[50,971,972],{"class":52,"line":90},[50,973,94],{"emptyLinePlaceholder":93},[50,975,976,979,981,983,985],{"class":52,"line":97},[50,977,978],{"class":56},"A x ",[50,980,61],{"class":60},[50,982,64],{"class":60},[50,984,928],{"class":67},[50,986,71],{"class":56},[50,988,989,992,995,998],{"class":52,"line":116},[50,990,991],{"class":56},"x.",[50,993,994],{"class":67},"v",[50,996,997],{"class":56},"();       ",[50,999,1000],{"class":86},"\u002F\u002F \"B\" via the override — dynamic binding (instance method)\n",[50,1002,1003,1005,1007,1010],{"class":52,"line":234},[50,1004,991],{"class":56},[50,1006,891],{"class":67},[50,1008,1009],{"class":56},"();     ",[50,1011,1012],{"class":86},"\u002F\u002F \"A\" — static method resolved by declared type A (hiding)\n",[50,1014,1015,1018],{"class":52,"line":399},[50,1016,1017],{"class":56},"x.f;         ",[50,1019,1020],{"class":86},"\u002F\u002F 1   — fields are not polymorphic; declared type A wins\n",[15,1022,1023,1024,1027,1028,1031,1032,460,1035,1038,1039,1042],{},"Because ",[23,1025,1026],{},"x.who()"," resolving to ",[23,1029,1030],{},"\"A\""," surprises almost everyone, ",[18,1033,1034],{},"always call static\nmethods on the class",[23,1036,1037],{},"A.who()","), never through an instance reference. Fields should be\n",[23,1040,1041],{},"private"," anyway, which sidesteps the hiding trap entirely.",[10,1044,1046],{"id":1045},"upcasting-downcasting-and-instanceof","Upcasting, downcasting, and instanceof",[15,1048,1049,1050,1053,1054,1057,1058,1061,1062,567,1065,1068,1069,1072,1073,471],{},"Polymorphism rests on ",[18,1051,1052],{},"upcasting"," — treating a subclass object as its supertype. It is\nimplicit and always safe because a ",[23,1055,1056],{},"Dog"," genuinely ",[32,1059,1060],{},"is an"," ",[23,1063,1064],{},"Animal",[18,1066,1067],{},"Downcasting"," goes\nthe other way, narrowing a supertype reference back to a subtype; it is explicit and can\nfail at runtime with a ",[23,1070,1071],{},"ClassCastException",", so you guard it with ",[23,1074,707],{},[41,1076,1078],{"className":43,"code":1077,"language":45,"meta":46,"style":46},"Animal a = new Dog();              \u002F\u002F upcast — implicit and always safe\n\nif (a instanceof Dog d) {          \u002F\u002F pattern matching (Java 16+) tests *and* binds\n  d.fetch();                       \u002F\u002F safe: d is a Dog inside this block\n}\n\nCat c = (Cat) a;                   \u002F\u002F unguarded downcast — ClassCastException at runtime!\n",[23,1079,1080,1096,1100,1116,1130,1134,1138],{"__ignoreMap":46},[50,1081,1082,1084,1086,1088,1090,1093],{"class":52,"line":53},[50,1083,57],{"class":56},[50,1085,61],{"class":60},[50,1087,64],{"class":60},[50,1089,68],{"class":67},[50,1091,1092],{"class":56},"();              ",[50,1094,1095],{"class":86},"\u002F\u002F upcast — implicit and always safe\n",[50,1097,1098],{"class":52,"line":74},[50,1099,94],{"emptyLinePlaceholder":93},[50,1101,1102,1105,1108,1110,1113],{"class":52,"line":90},[50,1103,1104],{"class":60},"if",[50,1106,1107],{"class":56}," (a ",[50,1109,707],{"class":60},[50,1111,1112],{"class":56}," Dog d) {          ",[50,1114,1115],{"class":86},"\u002F\u002F pattern matching (Java 16+) tests *and* binds\n",[50,1117,1118,1121,1124,1127],{"class":52,"line":97},[50,1119,1120],{"class":56},"  d.",[50,1122,1123],{"class":67},"fetch",[50,1125,1126],{"class":56},"();                       ",[50,1128,1129],{"class":86},"\u002F\u002F safe: d is a Dog inside this block\n",[50,1131,1132],{"class":52,"line":116},[50,1133,346],{"class":56},[50,1135,1136],{"class":52,"line":234},[50,1137,94],{"emptyLinePlaceholder":93},[50,1139,1140,1143,1145,1148],{"class":52,"line":399},[50,1141,1142],{"class":56},"Cat c ",[50,1144,61],{"class":60},[50,1146,1147],{"class":56}," (Cat) a;                   ",[50,1149,1150],{"class":86},"\u002F\u002F unguarded downcast — ClassCastException at runtime!\n",[15,1152,1153,1154,1156,1157,1160,1161,1166],{},"Reach for downcasting sparingly. A program littered with ",[23,1155,707],{},"\u002Fcast chains is often\na program that ",[32,1158,1159],{},"should"," have pushed the behavior into a virtual method. The modern\n",[18,1162,1163,1164],{},"pattern-matching ",[23,1165,707],{}," removes the redundant cast, but the design smell remains:\nif you're switching on type, a polymorphic method usually expresses it better.",[10,1168,1170],{"id":1169},"a-constructor-caveat-worth-remembering","A constructor caveat worth remembering",[15,1172,1173,1174,1177,1178,1181,1182,1185,1186,1189],{},"Dynamic dispatch is so eager it can bite you mid-construction. When a superclass constructor\ncalls an ",[18,1175,1176],{},"overridable"," method, the ",[18,1179,1180],{},"subclass override runs before the subclass's own\nfields are initialized"," — so it sees default ",[23,1183,1184],{},"null","\u002F",[23,1187,1188],{},"0"," values.",[41,1191,1193],{"className":43,"code":1192,"language":45,"meta":46,"style":46},"class Base { Base() { init(); } void init() { } }\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 — Base() runs init() before name is assigned\n",[23,1194,1195,1221,1233,1245,1267,1271],{"__ignoreMap":46},[50,1196,1197,1199,1201,1203,1206,1208,1211,1214,1216,1219],{"class":52,"line":53},[50,1198,306],{"class":60},[50,1200,309],{"class":67},[50,1202,883],{"class":56},[50,1204,1205],{"class":67},"Base",[50,1207,623],{"class":56},[50,1209,1210],{"class":67},"init",[50,1212,1213],{"class":56},"(); } ",[50,1215,182],{"class":60},[50,1217,1218],{"class":67}," init",[50,1220,921],{"class":56},[50,1222,1223,1225,1227,1229,1231],{"class":52,"line":74},[50,1224,306],{"class":60},[50,1226,353],{"class":67},[50,1228,356],{"class":60},[50,1230,309],{"class":67},[50,1232,312],{"class":56},[50,1234,1235,1238,1240,1243],{"class":52,"line":90},[50,1236,1237],{"class":56},"  String name ",[50,1239,61],{"class":60},[50,1241,1242],{"class":123}," \"set\"",[50,1244,540],{"class":56},[50,1246,1247,1249,1251,1253,1255,1258,1261,1264],{"class":52,"line":97},[50,1248,365],{"class":56},[50,1250,368],{"class":60},[50,1252,965],{"class":60},[50,1254,1218],{"class":67},[50,1256,1257],{"class":56},"() { System.out.",[50,1259,1260],{"class":67},"println",[50,1262,1263],{"class":56},"(name); }   ",[50,1265,1266],{"class":86},"\u002F\u002F prints null!\n",[50,1268,1269],{"class":52,"line":116},[50,1270,346],{"class":56},[50,1272,1273,1276,1278,1280],{"class":52,"line":234},[50,1274,1275],{"class":60},"new",[50,1277,353],{"class":67},[50,1279,816],{"class":56},[50,1281,1282],{"class":86},"\u002F\u002F null — Base() runs init() before name is assigned\n",[15,1284,1285,1286,1289,1290,1293,1294,1296],{},"The rule: ",[18,1287,1288],{},"never call overridable methods from a constructor."," Make such helpers ",[23,1291,1292],{},"final","\nor ",[23,1295,1041],{}," so dispatch can't reach a not-yet-built subclass.",[10,1298,1300],{"id":1299},"recap","Recap",[15,1302,1303,1304,1307,1308,1311,1312,1315,1316,1319,1320,1324,1325,1328,1329,1332,1333,1336,1337,1340,1341,1343],{},"Java polymorphism comes in two forms resolved at two times: ",[18,1305,1306],{},"overloading"," (compile-time,\nchosen by the compiler from declared argument types) and ",[18,1309,1310],{},"overriding"," (runtime, chosen by\nthe JVM from the actual object via ",[18,1313,1314],{},"dynamic dispatch","). Overriding follows strict rules on\n",[18,1317,1318],{},"signature, return type, access, and exceptions"," — guard every one with ",[18,1321,1322],{},[23,1323,415],{},".\nReturns may be ",[18,1326,1327],{},"covariant","; parameters may not. Remember the traps: ",[18,1330,1331],{},"fields and static\nmethods are hidden, not overridden"," (static binding by declared type), overloads resolve by\n",[18,1334,1335],{},"reference type not runtime value",", and ",[18,1338,1339],{},"constructors must never call overridable\nmethods",". Lean on upcasting and virtual calls instead of ",[23,1342,707],{}," chains, and your\ndesigns stay open to extension and free of type-switching clutter.",[1345,1346,1347],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":46,"searchDepth":74,"depth":74,"links":1349},[1350,1351,1352,1353,1354,1355,1356,1357,1358,1359],{"id":12,"depth":74,"text":13},{"id":133,"depth":74,"text":134},{"id":254,"depth":74,"text":255},{"id":419,"depth":74,"text":420},{"id":581,"depth":74,"text":582},{"id":711,"depth":74,"text":712},{"id":844,"depth":74,"text":845},{"id":1045,"depth":74,"text":1046},{"id":1169,"depth":74,"text":1170},{"id":1299,"depth":74,"text":1300},"How Java polymorphism really works — runtime vs compile-time, method overriding rules, overload resolution, dynamic dispatch, covariant returns, why fields and statics are hidden not overridden, and upcasting with instanceof.","medium","md","Java",{},"\u002Fblog\u002Fjava-polymorphism-overriding-overloading","\u002Fjava\u002Foop\u002Fpolymorphism",{"title":5,"description":1360},"blog\u002Fjava-polymorphism-overriding-overloading","Object-Oriented Programming","oop","2026-06-20","UybpDL4dxCf5x8RXZl_PzQsHvENW17cCFd3T2pyEeR8",1782244090164]