Abstract classes and interfaces
Inheritance and polymorphism showed what a subclass receives and how one call can mean many behaviors. This topic is about the other direction: what a type can demand from its implementers. Java has two ways to write that demand, and the difference between them is what each contract is allowed to carry.
An abstract class is a partial class. It can hold real state, like a battery field, and real behavior, like a working charge() method. But it can also leave a method abstract, a signature with no body, and that is the demand: any concrete subclass must implement doJob() or it will not compile. An abstract class says "here is what all Robots share, and here is what each of you must fill in."
An interface strips the contract down further. It names the methods an implementer must provide and, in its pure form, nothing else. It carries no instance state, so there is no battery that each robot carries around. An interface says only "whatever you are, you can do this."
That thinness is what buys the interface its superpower. A class can extend only one class, abstract or not, because inheriting state and behavior from two parents creates conflicts. But a class can implement any number of interfaces, because a promise to provide methods creates no conflict over state. Since Java 8 there is one exception: if two interfaces give the same method a default body, the class will not compile until it overrides that method and picks a winner. In the figure, GuardBot can take Alarmed alongside Robot, but only in interface mode.
The line has blurred in one place. Since Java 8, interfaces can carry default methods, implemented behavior that implementers inherit unless they override it. Turn on the charge() body and watch the contract: in abstract class mode the method is written plainly, and in interface mode the same method needs the default keyword. That keyword is the marker that says implementers get this body for free.
The state rule is the one that stays absolute. Add the battery field in interface mode and it still compiles, but the figure attaches a note: the field is implicitly a constant shared by every implementer, not per-object data. You can see the consequence inside charge(). In abstract class mode its body sets battery. In interface mode it cannot, because a constant cannot be reassigned, so the body does something else.
Both kinds of contract share one last restriction: neither can be instantiated. Press try new Robot() in either mode and the same thing happens, because a contract is not a thing, it is a shape for things.
A rough rule for choosing: use an abstract class when the implementers are close relatives that share state and code, and an interface when unrelated classes just need to make the same promise.
Building against a contract
Build GuardBot against a contract
Robot (the contract)abstract class Robot {int battery = 100; // instance state: allowedvoid charge() { battery = 100; } // implemented: allowedabstract void doJob(); // implementer MUST implement}
GuardBot (the implementer)class GuardBot extends Robot {void doJob() { ... }}
Every verdict above is computed from the same rule function against the toggles you set; nothing is hand-typed per combination. The "does not compile" cases are simulated, the same treatment as the Encapsulation figure: nothing is compiled in your browser.
- contract
- abstract class
- GuardBot
- extends Robot
- verdict
- compiles