Interfaces
A contract with no implementation attached: a list of method signatures a class promises to honor, and nothing about how it honors them. A class describes what an object is. An interface describes what an object can do.
A checkout flow that holds a PaymentMethod reference never learns whether it is
charging a card, debiting a wallet or moving a coin. Ship Apple Pay next year and the
checkout code does not change - one more class keeps the same promise, and nothing that
already worked notices the addition. This is the entire reason interfaces exist:
programming to an interface, not an implementation is one of the four
pillars (abstraction, specifically), and it is what Design
principles means when it talks about depending on an abstraction
rather than a concrete class - this page is where that idea gets its concrete tool.
Implementing multiple interfaces
A class can implement as many interfaces as it likes, because promising to do several unrelated things costs nothing until you actually write the methods:
Compare that to inheritance: a class extends exactly one other class in most languages, because it is inheriting real, concrete code, and resolving a conflict between two implementations of the same method from two parents ("diamond inheritance") is genuinely ambiguous. A conflict between two interfaces' method signatures is not ambiguous in the same way - there is no implementation to collide, only a name to promise.
Interface vs abstract class
Both let you program to an abstraction, and both show up constantly in machine-coding interviews, which is exactly why the distinction gets asked about directly.
| Interface | Abstract class | |
|---|---|---|
| Implementation | None - pure signatures (plus default/static methods in languages that allow them) | Can mix finished methods with abstract ones |
| State (fields) | No instance fields | Can hold instance fields |
| How many | A class can implement any number | A class can extend exactly one |
| Constructor | None | Can have one, run via super() |
| Use it when | Unrelated classes share only a signature | Subclasses share real, reusable implementation |
Reach for an interface when unrelated classes need to promise the same behavior and
nothing else - a Bird and an Airplane share zero code but can both promise fly().
Reach for an abstract class when subclasses genuinely share implementation and only differ
in specific, well-defined places - that shared code is the entire reason to inherit.
An abstract class earns its keep the moment two subclasses would otherwise duplicate the
same finished method. SalariedEmployee and HourlyEmployee both need to clockIn() and
clockOut() in an identical way; only calculatePay() actually differs between them.
That mix - some methods finished, one left as a promise - is exactly what a plain interface cannot offer on its own, since a plain interface cannot finish any method at all.
Default and static interface methods
Several languages (Java 8+, C# 8+, Kotlin) let an interface supply a method body directly, so implementers only need to override it if the default is wrong for them:
CreditCard and PayPal can override refund; a hypothetical GiftCard that never
supports refunds can simply not bother, and it still compiles because the interface
supplied a body. This blurs the line with an abstract class slightly, but the core
difference holds: a default method still cannot hold instance state, and a class can still
implement any number of interfaces that each bring default methods, which is not true of
abstract classes.
Static interface methods are the interface's equivalent of a static class method - a
utility function that belongs to the type, not to any implementer, like
Comparator.comparing(...) in Java's standard library.
Marker interfaces
An interface does not need to declare any methods at all. A marker interface - like
Java's Serializable or Cloneable - carries zero methods on purpose; implementing it is
itself the signal. Other code checks obj instanceof Serializable to decide whether an
object is allowed to be written to a stream, without calling any method the interface
defines, because it defines none. Modern code often reaches for an annotation instead
(@Serializable) for the same purpose, but the marker-interface shape still turns up in
older APIs and in languages without a first-class annotation system.
Try it yourself: Shape needs Circle, Square and Triangle to all expose
area(), sharing zero implementation. Separately, Employee needs SalariedEmployee
and HourlyEmployee to share clockIn()/clockOut() but calculate pay differently.
Which one gets an interface and which gets an abstract class, and why? Then: would a
Taggable marker interface with no methods make sense for flagging which of your classes
support a generic "add a label" feature, or would a plain boolean field on each class do
the same job with less machinery?
Check yourself
A checkout flow holds a PaymentMethod reference and calls pay(amount) without knowing if it is a CreditCard, PayPal or Crypto object. What made that possible?