[{"data":1,"prerenderedAt":1864},["ShallowReactive",2],{"blog-\u002Fblog\u002Fjava-interfaces-vs-abstract-classes":3},{"id":4,"title":5,"body":6,"description":1850,"difficulty":1851,"extension":1852,"framework":1853,"frameworkSlug":55,"meta":1854,"navigation":101,"order":122,"path":1855,"qaPath":1856,"seo":1857,"stem":1858,"subtopic":1859,"topic":1860,"topicSlug":1861,"updated":1862,"__hash__":1863},"blog\u002Fblog\u002Fjava-interfaces-vs-abstract-classes.md","Java Interfaces vs Abstract Classes — When to Use Which",{"type":7,"value":8,"toc":1836},"minimark",[9,14,36,40,50,199,206,210,253,488,505,509,527,689,696,700,732,912,946,950,960,1011,1030,1034,1063,1180,1190,1194,1211,1330,1343,1347,1376,1502,1521,1525,1552,1609,1622,1626,1633,1658,1731,1758,1762,1832],[10,11,13],"h2",{"id":12},"interfaces-vs-abstract-classes-in-java","Interfaces vs abstract classes in Java",[15,16,17,18,22,23,26,27,30,31,35],"p",{},"\"Interface or abstract class?\" is one of the most common Java design questions — in\ninterviews and in real code. Both let you program to an ",[19,20,21],"strong",{},"abstraction"," instead of a\nconcrete type, but they answer different needs. An abstract class is a ",[19,24,25],{},"partially built\nbase"," for a family of related classes; an interface is a ",[19,28,29],{},"contract"," any class can sign,\neven unrelated ones. Since Java 8 the line has blurred (interfaces now carry behavior), so\nthe real skill is knowing what each one ",[32,33,34],"em",{},"can't"," do and choosing on that basis. This guide\nwalks through both, the rules that govern conflicts between them, and the judgment that\nmakes the choice obvious.",[10,37,39],{"id":38},"abstraction-why-both-exist","Abstraction: why both exist",[15,41,42,45,46,49],{},[19,43,44],{},"Abstraction"," means exposing a ",[32,47,48],{},"simplified contract"," while hiding the implementation\nbehind it. Callers depend on the abstract type, not the concrete class — so you can swap\nimplementations freely. This is the heart of \"program to an interface, not an\nimplementation.\"",[51,52,57],"pre",{"className":53,"code":54,"language":55,"meta":56,"style":56},"language-java shiki shiki-themes github-light github-dark","interface PaymentGateway { void charge(int cents); }\n\nclass StripeGateway implements PaymentGateway {\n  public void charge(int cents) { \u002F* HTTP calls, retries, auth all hidden here *\u002F }\n}\n\nPaymentGateway gw = new StripeGateway(); \u002F\u002F calling code knows only the contract\ngw.charge(1999);                         \u002F\u002F swap in PayPalGateway later, no caller changes\n","java","",[58,59,60,96,103,120,147,153,158,178],"code",{"__ignoreMap":56},[61,62,65,69,73,77,80,83,86,89,93],"span",{"class":63,"line":64},"line",1,[61,66,68],{"class":67},"szBVR","interface",[61,70,72],{"class":71},"sScJk"," PaymentGateway",[61,74,76],{"class":75},"sVt8B"," { ",[61,78,79],{"class":67},"void",[61,81,82],{"class":71}," charge",[61,84,85],{"class":75},"(",[61,87,88],{"class":67},"int",[61,90,92],{"class":91},"s4XuR"," cents",[61,94,95],{"class":75},"); }\n",[61,97,99],{"class":63,"line":98},2,[61,100,102],{"emptyLinePlaceholder":101},true,"\n",[61,104,106,109,112,115,117],{"class":63,"line":105},3,[61,107,108],{"class":67},"class",[61,110,111],{"class":71}," StripeGateway",[61,113,114],{"class":67}," implements",[61,116,72],{"class":71},[61,118,119],{"class":75}," {\n",[61,121,123,126,129,131,133,135,137,140,144],{"class":63,"line":122},4,[61,124,125],{"class":67},"  public",[61,127,128],{"class":67}," void",[61,130,82],{"class":71},[61,132,85],{"class":75},[61,134,88],{"class":67},[61,136,92],{"class":91},[61,138,139],{"class":75},") { ",[61,141,143],{"class":142},"sJ8bj","\u002F* HTTP calls, retries, auth all hidden here *\u002F",[61,145,146],{"class":75}," }\n",[61,148,150],{"class":63,"line":149},5,[61,151,152],{"class":75},"}\n",[61,154,156],{"class":63,"line":155},6,[61,157,102],{"emptyLinePlaceholder":101},[61,159,161,164,167,170,172,175],{"class":63,"line":160},7,[61,162,163],{"class":75},"PaymentGateway gw ",[61,165,166],{"class":67},"=",[61,168,169],{"class":67}," new",[61,171,111],{"class":71},[61,173,174],{"class":75},"(); ",[61,176,177],{"class":142},"\u002F\u002F calling code knows only the contract\n",[61,179,181,184,187,189,193,196],{"class":63,"line":180},8,[61,182,183],{"class":75},"gw.",[61,185,186],{"class":71},"charge",[61,188,85],{"class":75},[61,190,192],{"class":191},"sj4cs","1999",[61,194,195],{"class":75},");                         ",[61,197,198],{"class":142},"\u002F\u002F swap in PayPalGateway later, no caller changes\n",[15,200,201,202,205],{},"Both interfaces and abstract classes give you this decoupling. The difference is ",[32,203,204],{},"how much","\nthey let you share alongside the contract — and that is what drives the choice.",[10,207,209],{"id":208},"what-an-abstract-class-can-do","What an abstract class can do",[15,211,212,213,216,217,220,221,224,225,228,229,232,233,236,237,240,241,244,245,248,249,252],{},"An ",[19,214,215],{},"abstract class"," is declared ",[58,218,219],{},"abstract"," and ",[19,222,223],{},"cannot be instantiated"," with ",[58,226,227],{},"new"," — it\nexists to be extended. Its superpower is that it can hold real ",[19,230,231],{},"state"," (instance fields),\ndefine a ",[19,234,235],{},"constructor",", and mix ",[19,238,239],{},"abstract methods"," (no body, subclasses must implement)\nwith ",[19,242,243],{},"concrete methods"," (shared implementation). A class ",[58,246,247],{},"extends"," exactly ",[19,250,251],{},"one",".",[51,254,256],{"className":53,"code":255,"language":55,"meta":56,"style":56},"abstract class Shape {\n  private final String name;          \u002F\u002F instance STATE — interfaces can't do this\n  Shape(String name) { this.name = name; } \u002F\u002F constructor runs during subclass construction\n\n  abstract double area();             \u002F\u002F subclasses MUST implement\n  String describe() {                 \u002F\u002F shared concrete behavior, reuses area()\n    return name + \" has area \" + area();\n  }\n}\nclass Circle extends Shape {\n  private final double r;\n  Circle(double r) { super(\"circle\"); this.r = r; } \u002F\u002F must chain to super(...)\n  double area() { return Math.PI * r * r; }\n}\n\u002F\u002F Shape s = new Shape(\"x\"); \u002F\u002F ERROR — abstract, cannot instantiate\n",[58,257,258,270,284,311,315,332,346,369,374,379,394,406,446,474,479],{"__ignoreMap":56},[61,259,260,262,265,268],{"class":63,"line":64},[61,261,219],{"class":67},[61,263,264],{"class":67}," class",[61,266,267],{"class":71}," Shape",[61,269,119],{"class":75},[61,271,272,275,278,281],{"class":63,"line":98},[61,273,274],{"class":67},"  private",[61,276,277],{"class":67}," final",[61,279,280],{"class":75}," String name;          ",[61,282,283],{"class":142},"\u002F\u002F instance STATE — interfaces can't do this\n",[61,285,286,289,292,295,297,300,303,305,308],{"class":63,"line":105},[61,287,288],{"class":71},"  Shape",[61,290,291],{"class":75},"(String ",[61,293,294],{"class":91},"name",[61,296,139],{"class":75},[61,298,299],{"class":191},"this",[61,301,302],{"class":75},".name ",[61,304,166],{"class":67},[61,306,307],{"class":75}," name; } ",[61,309,310],{"class":142},"\u002F\u002F constructor runs during subclass construction\n",[61,312,313],{"class":63,"line":122},[61,314,102],{"emptyLinePlaceholder":101},[61,316,317,320,323,326,329],{"class":63,"line":149},[61,318,319],{"class":67},"  abstract",[61,321,322],{"class":67}," double",[61,324,325],{"class":71}," area",[61,327,328],{"class":75},"();             ",[61,330,331],{"class":142},"\u002F\u002F subclasses MUST implement\n",[61,333,334,337,340,343],{"class":63,"line":155},[61,335,336],{"class":75},"  String ",[61,338,339],{"class":71},"describe",[61,341,342],{"class":75},"() {                 ",[61,344,345],{"class":142},"\u002F\u002F shared concrete behavior, reuses area()\n",[61,347,348,351,354,357,361,364,366],{"class":63,"line":160},[61,349,350],{"class":67},"    return",[61,352,353],{"class":75}," name ",[61,355,356],{"class":67},"+",[61,358,360],{"class":359},"sZZnC"," \" has area \"",[61,362,363],{"class":67}," +",[61,365,325],{"class":71},[61,367,368],{"class":75},"();\n",[61,370,371],{"class":63,"line":180},[61,372,373],{"class":75},"  }\n",[61,375,377],{"class":63,"line":376},9,[61,378,152],{"class":75},[61,380,382,384,387,390,392],{"class":63,"line":381},10,[61,383,108],{"class":67},[61,385,386],{"class":71}," Circle",[61,388,389],{"class":67}," extends",[61,391,267],{"class":71},[61,393,119],{"class":75},[61,395,397,399,401,403],{"class":63,"line":396},11,[61,398,274],{"class":67},[61,400,277],{"class":67},[61,402,322],{"class":67},[61,404,405],{"class":75}," r;\n",[61,407,409,412,414,417,420,422,425,427,430,433,435,438,440,443],{"class":63,"line":408},12,[61,410,411],{"class":71},"  Circle",[61,413,85],{"class":75},[61,415,416],{"class":67},"double",[61,418,419],{"class":91}," r",[61,421,139],{"class":75},[61,423,424],{"class":191},"super",[61,426,85],{"class":75},[61,428,429],{"class":359},"\"circle\"",[61,431,432],{"class":75},"); ",[61,434,299],{"class":191},[61,436,437],{"class":75},".r ",[61,439,166],{"class":67},[61,441,442],{"class":75}," r; } ",[61,444,445],{"class":142},"\u002F\u002F must chain to super(...)\n",[61,447,449,452,454,457,460,463,466,469,471],{"class":63,"line":448},13,[61,450,451],{"class":67},"  double",[61,453,325],{"class":71},[61,455,456],{"class":75},"() { ",[61,458,459],{"class":67},"return",[61,461,462],{"class":75}," Math.PI ",[61,464,465],{"class":67},"*",[61,467,468],{"class":75}," r ",[61,470,465],{"class":67},[61,472,473],{"class":75}," r; }\n",[61,475,477],{"class":63,"line":476},14,[61,478,152],{"class":75},[61,480,482,485],{"class":63,"line":481},15,[61,483,484],{"class":142},"\u002F\u002F Shape s = new Shape(\"x\");",[61,486,487],{"class":142}," \u002F\u002F ERROR — abstract, cannot instantiate\n",[15,489,490,491,494,495,497,498,501,502,252],{},"Note that a class with ",[19,492,493],{},"any"," abstract method must itself be ",[58,496,219],{}," — but an abstract\nclass is allowed to have ",[19,499,500],{},"zero"," abstract methods (sometimes useful purely to forbid\ndirect instantiation). Think of an abstract class as a ",[32,503,504],{},"half-finished base you're not meant\nto use directly",[10,506,508],{"id":507},"constructors-and-shared-state","Constructors and shared state",[15,510,511,512,515,516,518,519,522,523,526],{},"A frequent interview gotcha: ",[19,513,514],{},"can an abstract class have a constructor?"," Yes. You can't\n",[58,517,227],{}," it directly, but its constructor ",[19,520,521],{},"runs when a subclass is instantiated",", via the\nimplicit or explicit ",[58,524,525],{},"super(...)"," call. That's exactly how the abstract class initializes\nits slice of the object's state.",[51,528,530],{"className":53,"code":529,"language":55,"meta":56,"style":56},"abstract class Account {\n  protected final String owner;\n  private double balance;\n  Account(String owner) { this.owner = owner; } \u002F\u002F initializes shared state\n\n  void deposit(double amt) { balance += amt; }   \u002F\u002F shared, operates on shared state\n  abstract double interestRate();                 \u002F\u002F each subtype defines its own\n}\nclass Savings extends Account {\n  Savings(String owner) { super(owner); }         \u002F\u002F constructor chaining is mandatory\n  double interestRate() { return 0.04; }\n}\n",[58,531,532,543,553,562,587,591,618,633,637,650,669,685],{"__ignoreMap":56},[61,533,534,536,538,541],{"class":63,"line":64},[61,535,219],{"class":67},[61,537,264],{"class":67},[61,539,540],{"class":71}," Account",[61,542,119],{"class":75},[61,544,545,548,550],{"class":63,"line":98},[61,546,547],{"class":67},"  protected",[61,549,277],{"class":67},[61,551,552],{"class":75}," String owner;\n",[61,554,555,557,559],{"class":63,"line":105},[61,556,274],{"class":67},[61,558,322],{"class":67},[61,560,561],{"class":75}," balance;\n",[61,563,564,567,569,572,574,576,579,581,584],{"class":63,"line":122},[61,565,566],{"class":71},"  Account",[61,568,291],{"class":75},[61,570,571],{"class":91},"owner",[61,573,139],{"class":75},[61,575,299],{"class":191},[61,577,578],{"class":75},".owner ",[61,580,166],{"class":67},[61,582,583],{"class":75}," owner; } ",[61,585,586],{"class":142},"\u002F\u002F initializes shared state\n",[61,588,589],{"class":63,"line":149},[61,590,102],{"emptyLinePlaceholder":101},[61,592,593,596,599,601,603,606,609,612,615],{"class":63,"line":155},[61,594,595],{"class":67},"  void",[61,597,598],{"class":71}," deposit",[61,600,85],{"class":75},[61,602,416],{"class":67},[61,604,605],{"class":91}," amt",[61,607,608],{"class":75},") { balance ",[61,610,611],{"class":67},"+=",[61,613,614],{"class":75}," amt; }   ",[61,616,617],{"class":142},"\u002F\u002F shared, operates on shared state\n",[61,619,620,622,624,627,630],{"class":63,"line":160},[61,621,319],{"class":67},[61,623,322],{"class":67},[61,625,626],{"class":71}," interestRate",[61,628,629],{"class":75},"();                 ",[61,631,632],{"class":142},"\u002F\u002F each subtype defines its own\n",[61,634,635],{"class":63,"line":180},[61,636,152],{"class":75},[61,638,639,641,644,646,648],{"class":63,"line":376},[61,640,108],{"class":67},[61,642,643],{"class":71}," Savings",[61,645,389],{"class":67},[61,647,540],{"class":71},[61,649,119],{"class":75},[61,651,652,655,657,659,661,663,666],{"class":63,"line":381},[61,653,654],{"class":71},"  Savings",[61,656,291],{"class":75},[61,658,571],{"class":91},[61,660,139],{"class":75},[61,662,424],{"class":191},[61,664,665],{"class":75},"(owner); }         ",[61,667,668],{"class":142},"\u002F\u002F constructor chaining is mandatory\n",[61,670,671,673,675,677,679,682],{"class":63,"line":396},[61,672,451],{"class":67},[61,674,626],{"class":71},[61,676,456],{"class":75},[61,678,459],{"class":67},[61,680,681],{"class":191}," 0.04",[61,683,684],{"class":75},"; }\n",[61,686,687],{"class":63,"line":408},[61,688,152],{"class":75},[15,690,691,692,695],{},"Interfaces, by contrast, ",[19,693,694],{},"cannot"," have constructors — they have no instance state to\ninitialize. The moment your abstraction needs to set up shared mutable fields at\nconstruction time, you need an abstract class, not an interface.",[10,697,699],{"id":698},"what-an-interface-can-do","What an interface can do",[15,701,212,702,704,705,708,709,712,713,716,717,720,721,724,725,728,729,252],{},[19,703,68],{}," is a contract. Historically it held only abstract methods, but modern Java\ngives it ",[58,706,707],{},"default",", ",[58,710,711],{},"static",", and ",[58,714,715],{},"private"," methods too. The hard limits: ",[19,718,719],{},"no instance\nstate"," (only ",[58,722,723],{},"public static final"," constants), no constructors, and a class can implement\n",[19,726,727],{},"many"," interfaces. Every member is implicitly ",[58,730,731],{},"public",[51,733,735],{"className":53,"code":734,"language":55,"meta":56,"style":56},"interface Validator {\n  boolean valid(String s);                         \u002F\u002F abstract — the contract\n\n  static Validator notEmpty() {                    \u002F\u002F STATIC — factory tied to the type\n    return s -> s != null && !s.isEmpty();\n  }\n  default boolean validAll(List\u003CString> xs) {      \u002F\u002F DEFAULT — optional shared behavior\n    return xs.stream().allMatch(this::isOk);       \u002F\u002F delegates to a private helper\n  }\n  private boolean isOk(String s) { return valid(s); } \u002F\u002F PRIVATE — DRY for default methods\n}\n",[58,736,737,746,764,768,785,817,821,850,879,883,908],{"__ignoreMap":56},[61,738,739,741,744],{"class":63,"line":64},[61,740,68],{"class":67},[61,742,743],{"class":71}," Validator",[61,745,119],{"class":75},[61,747,748,751,754,756,759,761],{"class":63,"line":98},[61,749,750],{"class":67},"  boolean",[61,752,753],{"class":71}," valid",[61,755,291],{"class":75},[61,757,758],{"class":91},"s",[61,760,195],{"class":75},[61,762,763],{"class":142},"\u002F\u002F abstract — the contract\n",[61,765,766],{"class":63,"line":105},[61,767,102],{"emptyLinePlaceholder":101},[61,769,770,773,776,779,782],{"class":63,"line":122},[61,771,772],{"class":67},"  static",[61,774,775],{"class":75}," Validator ",[61,777,778],{"class":71},"notEmpty",[61,780,781],{"class":75},"() {                    ",[61,783,784],{"class":142},"\u002F\u002F STATIC — factory tied to the type\n",[61,786,787,789,792,795,797,800,803,806,809,812,815],{"class":63,"line":149},[61,788,350],{"class":67},[61,790,791],{"class":75}," s ",[61,793,794],{"class":67},"->",[61,796,791],{"class":75},[61,798,799],{"class":67},"!=",[61,801,802],{"class":191}," null",[61,804,805],{"class":67}," &&",[61,807,808],{"class":67}," !",[61,810,811],{"class":75},"s.",[61,813,814],{"class":71},"isEmpty",[61,816,368],{"class":75},[61,818,819],{"class":63,"line":155},[61,820,373],{"class":75},[61,822,823,826,829,832,835,838,841,844,847],{"class":63,"line":160},[61,824,825],{"class":67},"  default",[61,827,828],{"class":67}," boolean",[61,830,831],{"class":71}," validAll",[61,833,834],{"class":75},"(List\u003C",[61,836,837],{"class":67},"String",[61,839,840],{"class":75},"> ",[61,842,843],{"class":91},"xs",[61,845,846],{"class":75},") {      ",[61,848,849],{"class":142},"\u002F\u002F DEFAULT — optional shared behavior\n",[61,851,852,854,857,860,863,866,868,870,873,876],{"class":63,"line":180},[61,853,350],{"class":67},[61,855,856],{"class":75}," xs.",[61,858,859],{"class":71},"stream",[61,861,862],{"class":75},"().",[61,864,865],{"class":71},"allMatch",[61,867,85],{"class":75},[61,869,299],{"class":191},[61,871,872],{"class":67},"::",[61,874,875],{"class":75},"isOk);       ",[61,877,878],{"class":142},"\u002F\u002F delegates to a private helper\n",[61,880,881],{"class":63,"line":376},[61,882,373],{"class":75},[61,884,885,887,889,892,894,896,898,900,902,905],{"class":63,"line":381},[61,886,274],{"class":67},[61,888,828],{"class":67},[61,890,891],{"class":71}," isOk",[61,893,291],{"class":75},[61,895,758],{"class":91},[61,897,139],{"class":75},[61,899,459],{"class":67},[61,901,753],{"class":71},[61,903,904],{"class":75},"(s); } ",[61,906,907],{"class":142},"\u002F\u002F PRIVATE — DRY for default methods\n",[61,909,910],{"class":63,"line":396},[61,911,152],{"class":75},[15,913,914,915,919,920,923,924,927,928,931,932,936,937,940,941,945],{},"The three method flavors each earn their keep: ",[19,916,917],{},[58,918,707],{}," lets interfaces ",[19,921,922],{},"evolve","\nwithout breaking implementers (this is how ",[58,925,926],{},"forEach"," was added to ",[58,929,930],{},"Iterable"," in Java 8);\n",[19,933,934],{},[58,935,711],{}," holds factories and utilities tied to the type (like ",[58,938,939],{},"Comparator.comparing",");\n",[19,942,943],{},[58,944,715],{}," lets default\u002Fstatic methods share code without exposing it. Interfaces are now\nmini-toolkits, but still pure of mutable state.",[10,947,949],{"id":948},"constants-not-fields","Constants, not fields",[15,951,952,953,956,957,959],{},"Interfaces can hold data — but only ",[19,954,955],{},"constants",". Every field is implicitly\n",[58,958,723],{},", so it must be initialized at declaration and can never change. There\nis no per-instance storage.",[51,961,963],{"className":53,"code":962,"language":55,"meta":56,"style":56},"interface Physics {\n  double SPEED_OF_LIGHT = 299_792_458; \u002F\u002F implicitly public static final\n}\ndouble c = Physics.SPEED_OF_LIGHT;     \u002F\u002F access through the interface name\n",[58,964,965,974,992,996],{"__ignoreMap":56},[61,966,967,969,972],{"class":63,"line":64},[61,968,68],{"class":67},[61,970,971],{"class":71}," Physics",[61,973,119],{"class":75},[61,975,976,978,981,983,986,989],{"class":63,"line":98},[61,977,451],{"class":67},[61,979,980],{"class":75}," SPEED_OF_LIGHT ",[61,982,166],{"class":67},[61,984,985],{"class":191}," 299_792_458",[61,987,988],{"class":75},"; ",[61,990,991],{"class":142},"\u002F\u002F implicitly public static final\n",[61,993,994],{"class":63,"line":105},[61,995,152],{"class":75},[61,997,998,1000,1003,1005,1008],{"class":63,"line":122},[61,999,416],{"class":67},[61,1001,1002],{"class":75}," c ",[61,1004,166],{"class":67},[61,1006,1007],{"class":75}," Physics.SPEED_OF_LIGHT;     ",[61,1009,1010],{"class":142},"\u002F\u002F access through the interface name\n",[15,1012,1013,1014,1017,1018,1021,1022,1025,1026,1029],{},"Beware the old ",[19,1015,1016],{},"\"constant interface\" anti-pattern"," — implementing an interface ",[32,1019,1020],{},"just"," to\ninherit its constants pollutes your type's public API with an implementation detail. Prefer\nan ",[58,1023,1024],{},"enum"," or a ",[58,1027,1028],{},"final"," class with a private constructor for grouped constants. An interface\nholds constants and behavior; never mutable state.",[10,1031,1033],{"id":1032},"multiple-inheritance-of-type","Multiple inheritance of type",[15,1035,1036,1037,1040,1042,1043,1045,1046,1048,1049,1052,1053,1056,1057,1059,1060,252],{},"The single biggest practical reason to reach for an interface: a class can ",[58,1038,1039],{},"implements",[19,1041,727],{}," interfaces, but ",[58,1044,247],{}," only ",[19,1047,251],{}," class. Interfaces give Java multiple\ninheritance of ",[32,1050,1051],{},"type"," (and, since Java 8, of ",[32,1054,1055],{},"behavior"," via defaults) without multiple\ninheritance of ",[32,1058,231],{}," — which is what causes the classic ",[19,1061,1062],{},"diamond problem",[51,1064,1066],{"className":53,"code":1065,"language":55,"meta":56,"style":56},"interface Swimmer { default void move()  { System.out.println(\"swim\");  } }\ninterface Flyer   { default void glide() { System.out.println(\"glide\"); } }\n\nclass Duck implements Swimmer, Flyer { } \u002F\u002F inherits BOTH capabilities, no conflict\nnew Duck().move();\nnew Duck().glide();\n",[58,1067,1068,1098,1128,1132,1154,1167],{"__ignoreMap":56},[61,1069,1070,1072,1075,1077,1079,1081,1084,1087,1090,1092,1095],{"class":63,"line":64},[61,1071,68],{"class":67},[61,1073,1074],{"class":71}," Swimmer",[61,1076,76],{"class":75},[61,1078,707],{"class":67},[61,1080,128],{"class":67},[61,1082,1083],{"class":71}," move",[61,1085,1086],{"class":75},"()  { System.out.",[61,1088,1089],{"class":71},"println",[61,1091,85],{"class":75},[61,1093,1094],{"class":359},"\"swim\"",[61,1096,1097],{"class":75},");  } }\n",[61,1099,1100,1102,1105,1108,1110,1112,1115,1118,1120,1122,1125],{"class":63,"line":98},[61,1101,68],{"class":67},[61,1103,1104],{"class":71}," Flyer",[61,1106,1107],{"class":75},"   { ",[61,1109,707],{"class":67},[61,1111,128],{"class":67},[61,1113,1114],{"class":71}," glide",[61,1116,1117],{"class":75},"() { System.out.",[61,1119,1089],{"class":71},[61,1121,85],{"class":75},[61,1123,1124],{"class":359},"\"glide\"",[61,1126,1127],{"class":75},"); } }\n",[61,1129,1130],{"class":63,"line":105},[61,1131,102],{"emptyLinePlaceholder":101},[61,1133,1134,1136,1139,1141,1143,1145,1148,1151],{"class":63,"line":122},[61,1135,108],{"class":67},[61,1137,1138],{"class":71}," Duck",[61,1140,114],{"class":67},[61,1142,1074],{"class":71},[61,1144,708],{"class":75},[61,1146,1147],{"class":71},"Flyer",[61,1149,1150],{"class":75}," { } ",[61,1152,1153],{"class":142},"\u002F\u002F inherits BOTH capabilities, no conflict\n",[61,1155,1156,1158,1160,1162,1165],{"class":63,"line":149},[61,1157,227],{"class":67},[61,1159,1138],{"class":71},[61,1161,862],{"class":75},[61,1163,1164],{"class":71},"move",[61,1166,368],{"class":75},[61,1168,1169,1171,1173,1175,1178],{"class":63,"line":155},[61,1170,227],{"class":67},[61,1172,1138],{"class":71},[61,1174,862],{"class":75},[61,1176,1177],{"class":71},"glide",[61,1179,368],{"class":75},[15,1181,1182,1183,1186,1187,252],{},"Because interfaces hold no instance fields, there is no ambiguous state to merge — that's\nprecisely why Java permits multiple interfaces but only single class inheritance. Interfaces\nare safe multiple inheritance of ",[32,1184,1185],{},"capability","; classes are single inheritance of\n",[32,1188,1189],{},"implementation",[10,1191,1193],{"id":1192},"resolving-default-method-conflicts","Resolving default-method conflicts",[15,1195,1196,1197,1202,1203,1206,1207,1210],{},"Multiple inheritance of behavior does introduce one ambiguity: what if two interfaces supply\n",[19,1198,1199,1200],{},"conflicting ",[58,1201,707],{}," methods? The compiler refuses to guess — the class ",[19,1204,1205],{},"must\noverride"," to break the tie, and can delegate to a specific parent with the special\n",[58,1208,1209],{},"Interface.super.method()"," syntax.",[51,1212,1214],{"className":53,"code":1213,"language":55,"meta":56,"style":56},"interface A { default String hi() { return \"A\"; } }\ninterface B { default String hi() { return \"B\"; } }\n\nclass C implements A, B {\n  @Override public String hi() {\n    return A.super.hi();   \u002F\u002F explicitly pick A's default (or write your own)\n  }\n}\n",[58,1215,1216,1243,1267,1271,1289,1307,1322,1326],{"__ignoreMap":56},[61,1217,1218,1220,1223,1225,1227,1230,1233,1235,1237,1240],{"class":63,"line":64},[61,1219,68],{"class":67},[61,1221,1222],{"class":71}," A",[61,1224,76],{"class":75},[61,1226,707],{"class":67},[61,1228,1229],{"class":75}," String ",[61,1231,1232],{"class":71},"hi",[61,1234,456],{"class":75},[61,1236,459],{"class":67},[61,1238,1239],{"class":359}," \"A\"",[61,1241,1242],{"class":75},"; } }\n",[61,1244,1245,1247,1250,1252,1254,1256,1258,1260,1262,1265],{"class":63,"line":98},[61,1246,68],{"class":67},[61,1248,1249],{"class":71}," B",[61,1251,76],{"class":75},[61,1253,707],{"class":67},[61,1255,1229],{"class":75},[61,1257,1232],{"class":71},[61,1259,456],{"class":75},[61,1261,459],{"class":67},[61,1263,1264],{"class":359}," \"B\"",[61,1266,1242],{"class":75},[61,1268,1269],{"class":63,"line":105},[61,1270,102],{"emptyLinePlaceholder":101},[61,1272,1273,1275,1278,1280,1282,1284,1287],{"class":63,"line":122},[61,1274,108],{"class":67},[61,1276,1277],{"class":71}," C",[61,1279,114],{"class":67},[61,1281,1222],{"class":71},[61,1283,708],{"class":75},[61,1285,1286],{"class":71},"B",[61,1288,119],{"class":75},[61,1290,1291,1294,1297,1300,1302,1304],{"class":63,"line":149},[61,1292,1293],{"class":75},"  @",[61,1295,1296],{"class":67},"Override",[61,1298,1299],{"class":67}," public",[61,1301,1229],{"class":75},[61,1303,1232],{"class":71},[61,1305,1306],{"class":75},"() {\n",[61,1308,1309,1311,1314,1316,1319],{"class":63,"line":155},[61,1310,350],{"class":67},[61,1312,1313],{"class":75}," A.super.",[61,1315,1232],{"class":71},[61,1317,1318],{"class":75},"();   ",[61,1320,1321],{"class":142},"\u002F\u002F explicitly pick A's default (or write your own)\n",[61,1323,1324],{"class":63,"line":160},[61,1325,373],{"class":75},[61,1327,1328],{"class":63,"line":180},[61,1329,152],{"class":75},[15,1331,1332,1333,1336,1337,1339,1340,252],{},"There's also a precedence rule when a class and an interface collide: ",[19,1334,1335],{},"class always beats\ninterface",". A concrete method inherited from a superclass wins over an interface ",[58,1338,707],{},",\neven if the interface seems \"more specific.\" Among interfaces alone, a more-specific\nsubinterface's default beats a less-specific one; genuine ties you resolve by hand. The\nordering to memorize: ",[19,1341,1342],{},"superclass method > interface default > you must override",[10,1344,1346],{"id":1345},"functional-interfaces","Functional interfaces",[15,1348,1349,1350,1353,1354,1357,1358,1361,1362,1365,1366,1368,1369,1371,1372,1375],{},"A ",[19,1351,1352],{},"functional interface"," has exactly ",[19,1355,1356],{},"one abstract method"," (SAM — Single Abstract\nMethod), which makes it the target type of a ",[19,1359,1360],{},"lambda"," or ",[19,1363,1364],{},"method reference",". ",[58,1367,707],{},"\nand ",[58,1370,711],{}," methods don't count against the limit. The ",[58,1373,1374],{},"@FunctionalInterface"," annotation\nasks the compiler to enforce the one-abstract-method rule, so an accidental second abstract\nmethod becomes a compile error.",[51,1377,1379],{"className":53,"code":1378,"language":55,"meta":56,"style":56},"@FunctionalInterface\ninterface Transformer {\n  String apply(String s);                 \u002F\u002F the single abstract method (SAM)\n  default Transformer andTrim() {         \u002F\u002F defaults don't break the SAM rule\n    return s -> apply(s).trim();\n  }\n}\n\nTransformer upper = s -> s.toUpperCase(); \u002F\u002F lambda implements the SAM\nupper.apply(\"  hi  \");                     \u002F\u002F \"  HI  \"\n",[58,1380,1381,1389,1398,1415,1431,1450,1454,1458,1462,1484],{"__ignoreMap":56},[61,1382,1383,1386],{"class":63,"line":64},[61,1384,1385],{"class":75},"@",[61,1387,1388],{"class":67},"FunctionalInterface\n",[61,1390,1391,1393,1396],{"class":63,"line":98},[61,1392,68],{"class":67},[61,1394,1395],{"class":71}," Transformer",[61,1397,119],{"class":75},[61,1399,1400,1402,1405,1407,1409,1412],{"class":63,"line":105},[61,1401,336],{"class":75},[61,1403,1404],{"class":71},"apply",[61,1406,291],{"class":75},[61,1408,758],{"class":91},[61,1410,1411],{"class":75},");                 ",[61,1413,1414],{"class":142},"\u002F\u002F the single abstract method (SAM)\n",[61,1416,1417,1419,1422,1425,1428],{"class":63,"line":122},[61,1418,825],{"class":67},[61,1420,1421],{"class":75}," Transformer ",[61,1423,1424],{"class":71},"andTrim",[61,1426,1427],{"class":75},"() {         ",[61,1429,1430],{"class":142},"\u002F\u002F defaults don't break the SAM rule\n",[61,1432,1433,1435,1437,1439,1442,1445,1448],{"class":63,"line":149},[61,1434,350],{"class":67},[61,1436,791],{"class":75},[61,1438,794],{"class":67},[61,1440,1441],{"class":71}," apply",[61,1443,1444],{"class":75},"(s).",[61,1446,1447],{"class":71},"trim",[61,1449,368],{"class":75},[61,1451,1452],{"class":63,"line":155},[61,1453,373],{"class":75},[61,1455,1456],{"class":63,"line":160},[61,1457,152],{"class":75},[61,1459,1460],{"class":63,"line":180},[61,1461,102],{"emptyLinePlaceholder":101},[61,1463,1464,1467,1469,1471,1473,1476,1479,1481],{"class":63,"line":376},[61,1465,1466],{"class":75},"Transformer upper ",[61,1468,166],{"class":67},[61,1470,791],{"class":75},[61,1472,794],{"class":67},[61,1474,1475],{"class":75}," s.",[61,1477,1478],{"class":71},"toUpperCase",[61,1480,174],{"class":75},[61,1482,1483],{"class":142},"\u002F\u002F lambda implements the SAM\n",[61,1485,1486,1489,1491,1493,1496,1499],{"class":63,"line":381},[61,1487,1488],{"class":75},"upper.",[61,1490,1404],{"class":71},[61,1492,85],{"class":75},[61,1494,1495],{"class":359},"\"  hi  \"",[61,1497,1498],{"class":75},");                     ",[61,1500,1501],{"class":142},"\u002F\u002F \"  HI  \"\n",[15,1503,1504,1505,708,1508,708,1511,708,1514,708,1517,1520],{},"The JDK is full of these: ",[58,1506,1507],{},"Runnable",[58,1509,1510],{},"Comparator",[58,1512,1513],{},"Function",[58,1515,1516],{},"Predicate",[58,1518,1519],{},"Supplier",".\nThis is one capability abstract classes simply can't offer — you cannot write a lambda for\nan abstract class. If you want your abstraction to be lambda-friendly, it has to be a\nsingle-method interface.",[10,1522,1524],{"id":1523},"marker-interfaces","Marker interfaces",[15,1526,1349,1527,1530,1531,1534,1535,1538,1539,1542,1543,708,1546,712,1549,252],{},[19,1528,1529],{},"marker interface"," has ",[19,1532,1533],{},"no methods at all"," — it exists purely to ",[32,1536,1537],{},"tag"," a class so code\nor the JVM can detect a capability at runtime via ",[58,1540,1541],{},"instanceof",". The classic examples are\n",[58,1544,1545],{},"Serializable",[58,1547,1548],{},"Cloneable",[58,1550,1551],{},"RandomAccess",[51,1553,1555],{"className":53,"code":1554,"language":55,"meta":56,"style":56},"class Config implements Serializable { } \u002F\u002F \"instances of this class may be serialized\"\n\nObject o = new Config();\nif (o instanceof Serializable) { \u002F* the JVM checks exactly this before serializing *\u002F }\n",[58,1556,1557,1574,1578,1591],{"__ignoreMap":56},[61,1558,1559,1561,1564,1566,1569,1571],{"class":63,"line":64},[61,1560,108],{"class":67},[61,1562,1563],{"class":71}," Config",[61,1565,114],{"class":67},[61,1567,1568],{"class":71}," Serializable",[61,1570,1150],{"class":75},[61,1572,1573],{"class":142},"\u002F\u002F \"instances of this class may be serialized\"\n",[61,1575,1576],{"class":63,"line":98},[61,1577,102],{"emptyLinePlaceholder":101},[61,1579,1580,1583,1585,1587,1589],{"class":63,"line":105},[61,1581,1582],{"class":75},"Object o ",[61,1584,166],{"class":67},[61,1586,169],{"class":67},[61,1588,1563],{"class":71},[61,1590,368],{"class":75},[61,1592,1593,1596,1599,1601,1604,1607],{"class":63,"line":122},[61,1594,1595],{"class":67},"if",[61,1597,1598],{"class":75}," (o ",[61,1600,1541],{"class":67},[61,1602,1603],{"class":75}," Serializable) { ",[61,1605,1606],{"class":142},"\u002F* the JVM checks exactly this before serializing *\u002F",[61,1608,146],{"class":75},[15,1610,1611,1612,1615,1616,1618,1619,1621],{},"Modern Java often prefers ",[19,1613,1614],{},"annotations"," for metadata, but marker interfaces still give you\ntwo things annotations don't: a real ",[19,1617,1051],{}," you can use in method signatures and a\ncompile-time check via ",[58,1620,1541],{},". They're a niche but legitimate use of interfaces with\nno abstract-class equivalent.",[10,1623,1625],{"id":1624},"when-to-choose-which","When to choose which",[15,1627,1628,1629,1632],{},"Decide by ",[19,1630,1631],{},"what you need to share",":",[1634,1635,1636,1646],"ul",{},[1637,1638,1639,1640,1642,1643,1645],"li",{},"Reach for an ",[19,1641,68],{}," when you're defining a ",[32,1644,1185],{}," that unrelated classes can\nhave, when you need multiple inheritance of type, or when you want a lambda target. No\nshared state.",[1637,1647,1639,1648,1650,1651,1654,1655,252],{},[19,1649,215],{}," when you have a ",[32,1652,1653],{},"family"," of related classes that share\n",[19,1656,1657],{},"fields, a constructor, or substantial implementation",[51,1659,1661],{"className":53,"code":1660,"language":55,"meta":56,"style":56},"interface Comparable\u003CT> { int compareTo(T o); } \u002F\u002F any class can opt into being comparable\nabstract class HttpServlet {                     \u002F\u002F a family sharing request\u002Fresponse plumbing\n  protected void service() { \u002F* shared template logic, calls abstract hooks *\u002F }\n}\n",[58,1662,1663,1696,1711,1727],{"__ignoreMap":56},[61,1664,1665,1667,1670,1673,1676,1679,1681,1684,1687,1690,1693],{"class":63,"line":64},[61,1666,68],{"class":67},[61,1668,1669],{"class":71}," Comparable",[61,1671,1672],{"class":75},"\u003C",[61,1674,1675],{"class":67},"T",[61,1677,1678],{"class":75},"> { ",[61,1680,88],{"class":67},[61,1682,1683],{"class":71}," compareTo",[61,1685,1686],{"class":75},"(T ",[61,1688,1689],{"class":91},"o",[61,1691,1692],{"class":75},"); } ",[61,1694,1695],{"class":142},"\u002F\u002F any class can opt into being comparable\n",[61,1697,1698,1700,1702,1705,1708],{"class":63,"line":98},[61,1699,219],{"class":67},[61,1701,264],{"class":67},[61,1703,1704],{"class":71}," HttpServlet",[61,1706,1707],{"class":75}," {                     ",[61,1709,1710],{"class":142},"\u002F\u002F a family sharing request\u002Fresponse plumbing\n",[61,1712,1713,1715,1717,1720,1722,1725],{"class":63,"line":105},[61,1714,547],{"class":67},[61,1716,128],{"class":67},[61,1718,1719],{"class":71}," service",[61,1721,456],{"class":75},[61,1723,1724],{"class":142},"\u002F* shared template logic, calls abstract hooks *\u002F",[61,1726,146],{"class":75},[61,1728,1729],{"class":63,"line":122},[61,1730,152],{"class":75},[15,1732,1733,1734,1737,1738,1741,1742,1745,1746,1749,1750,1753,1754,1757],{},"In practice they ",[19,1735,1736],{},"combine"," beautifully: declare the public API as an interface, then offer\nan optional ",[58,1739,1740],{},"AbstractXxx"," ",[32,1743,1744],{},"skeletal implementation"," for implementers who want the shared\nplumbing — exactly the ",[58,1747,1748],{},"List"," \u002F ",[58,1751,1752],{},"AbstractList"," pattern in the JDK. The default heuristic:\n",[19,1755,1756],{},"start with an interface",", and only promote to (or add) an abstract class when you must\nshare state or a real chunk of implementation.",[10,1759,1761],{"id":1760},"recap","Recap",[15,1763,212,1764,1766,1767,1769,1770,1772,1773,1045,1775,1777,1778,1780,1781,1783,1784,1783,1786,1788,1789,1741,1791,1793,1794,1797,1798,1741,1800,1802,1803,220,1805,1807,1808,1810,1811,1814,1815,1818,1819,1821,1822,1825,1826,1828,1829,1831],{},[19,1765,215],{}," is a half-built base for a tight family of related types — it can hold\n",[19,1768,231],{},", a ",[19,1771,235],{},", and a mix of concrete and abstract methods, but a class\n",[58,1774,247],{},[19,1776,251],{},". An ",[19,1779,68],{}," is a contract any class can sign: it allows\n",[58,1782,707],{},"\u002F",[58,1785,711],{},[58,1787,715],{}," methods and ",[58,1790,723],{},[19,1792,955],{},", but ",[19,1795,1796],{},"no\ninstance state"," and no constructors, and a class ",[58,1799,1039],{},[19,1801,727],{}," — giving Java safe\nmultiple inheritance of ",[32,1804,1051],{},[32,1806,1055],{},". Conflicting defaults force an override\n(",[58,1809,1209],{},"), and ",[19,1812,1813],{},"class beats interface"," when they collide. Remember the\nspecialized interface roles — ",[19,1816,1817],{},"functional interfaces"," for lambdas (SAM +\n",[58,1820,1374],{},") and ",[19,1823,1824],{},"marker interfaces"," for ",[58,1827,1541],{}," tagging. Default to an\ninterface; reach for an abstract class only when shared state or implementation demands it,\nand combine them via skeletal ",[58,1830,1740],{}," classes when you want both.",[1833,1834,1835],"style",{},"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 .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}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 .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);}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}",{"title":56,"searchDepth":98,"depth":98,"links":1837},[1838,1839,1840,1841,1842,1843,1844,1845,1846,1847,1848,1849],{"id":12,"depth":98,"text":13},{"id":38,"depth":98,"text":39},{"id":208,"depth":98,"text":209},{"id":507,"depth":98,"text":508},{"id":698,"depth":98,"text":699},{"id":948,"depth":98,"text":949},{"id":1032,"depth":98,"text":1033},{"id":1192,"depth":98,"text":1193},{"id":1345,"depth":98,"text":1346},{"id":1523,"depth":98,"text":1524},{"id":1624,"depth":98,"text":1625},{"id":1760,"depth":98,"text":1761},"Java interfaces vs abstract classes explained — abstraction, default\u002Fstatic\u002Fprivate interface methods, functional and marker interfaces, multiple inheritance of type, default-method conflict resolution, and how to choose the right one in interviews.","medium","md","Java",{},"\u002Fblog\u002Fjava-interfaces-vs-abstract-classes","\u002Fjava\u002Foop\u002Finterfaces-vs-abstract",{"title":5,"description":1850},"blog\u002Fjava-interfaces-vs-abstract-classes","Interfaces vs Abstract Classes","Object-Oriented Programming","oop","2026-06-20","2S0xogZcKeSZabatKZNTRXhF6n1TA9lz44I4ex3gvlQ",1782244090562]