Abstract Classes and Methods
A Java interface is a reserved word that introduces a set of instance method declarations with no implementations.
Try it: Inheritance and Method Lookup
How a subclass inherits from its parent, how Python finds an attribute by walking the instance, then the class's method resolution order up to object, how overriding and super() work, why the same call does different things on different objects (polymorphism), and what isinstance / issubclass check.
How it works
- class Dog(Animal) gives Dog the MRO Dog → Animal → object; Puppy(Dog) gives Puppy → Dog → Animal → object.
- obj.name searches obj.__dict__, then each class of type(obj).__mro__ in order; the first class that defines the name wins, so a subclass method overrides the parent's.
- super().method() starts the search in the class after the one the current method was defined in, e.g. to run the parent's __init__.
- Calling the same method on a list of different objects runs each object's own version (polymorphism).
- isinstance(obj, C) is True when C is in type(obj).__mro__; if no class has the name, Python raises AttributeError.
Default run (63 steps): Ready: Animal, Dog, Cat and Puppy, then the statements you picked. Each attribute is searched along the class's MRO. … Finished. Printed: Rex the dog says Woof / Tom the cat says Meow / Bo the dog says Woof! / True / Puppy / Dog / Animal / object.
Simplified: The lab's own small Python interpreter runs a fixed, hand-written script (you choose the variant and the values, never the code); nothing is executed as real Python. Every script was run in CPython 3.12 with the same inputs and the lab reproduces its output and error messages. Single inheritance only (the lab's MRO code is Python's C3 algorithm, but no class here has two parents).
Loading the simulation…
A Drawing Program That Needs a Promise
Imagine a drawing program where many different shapes need to be painted onto a screen. The drawing code wants to say, simply, stroke this shape with a pen. It does not care whether the shape is a circle, a polygon, or a piece of text. What it needs is a guarantee that every shape it receives knows how to be stroked. Java gives you a construct for writing down that guarantee without writing any of the drawing logic itself. That construct is called an interface.
This article follows one thread through two related ideas. First, what an interface contains and which rules govern the things placed inside it. Second, what an abstract class is and why a superclass sometimes declares a method that has no meaningful body. As you read, keep one idea in mind: the interface describes a promise, and a class is the thing that keeps it.
What an Interface Declaration Holds
A Java interface is a reserved word that introduces a set of instance method declarations with no implementations. The word interface is reserved, which means the language sets it aside for this purpose and you cannot use it as an ordinary name. A declaration gives a method's name, its parameters, and its return type. An implementation supplies the body that actually does the work. An interface gives only the declarations.
public interface Strokeable {
void stroke(Graphics g);
}- 1Line 1 opens the interface named Strokeable.
- 2Line 2 declares the method stroke. Its body is absent, so it ends in a semicolon.
- 3Line 3 closes the interface.
- The keyword interface opens the definition, and Strokeable is the name chosen for it.
- Inside the braces sits one declaration, stroke, which accepts one Graphics parameter.
- The semicolon ends the declaration. There is no body with curly braces, because the interface does not provide one.
The body would belong to whichever class eventually implements Strokeable. A class implements an interface by providing an implementation for each method the interface specifies. So the interface defines what must be available, and the implementing class decides how it works.
Predict Before You Read the Rule
What do you think happens?
Suppose a class declares that it implements Strokeable, but the class contains no code for the stroke method. Does the class compile?
Reveal answer
No, the compiler rejects the class because it does not satisfy the interface.
The interface promises that stroke exists, and the class has agreed to keep that promise by implementing it. A class that claims the interface but omits a required method has broken its agreement, and the compiler reports that failure.
Method Modifiers in an Interface
Every method declared in an interface must be public and abstract. The reason this is a rule rather than a choice is that public and abstract are the only options available for interface methods. Because there is no other possibility, Java does not require you to write either modifier. The two forms below mean the same thing to the compiler.
The rule concerns the declaration only. Writing or omitting modifiers changes how the text reads, not what the interface requires. When you see a method inside an interface, you can safely assume it is public and abstract even when those keywords are missing from the page.
Variables Inside an Interface
An interface can also hold variable declarations, not only method declarations. The source requires these variables to be public, static, and final. The effect is that each variable becomes a public static final variable in every class that implements the interface. The interface therefore acts as a shared place to define fixed values that any implementing class can use.
- INCHES_PER_FOOT is a constant: one name tied to one fixed number.
- No public static final is written, because the interface implies them.
Because the variables can only be public, static, and final, Java does not need you to write those modifiers. The declaration int INCHES_PER_FOOT = 12; carries the full meaning on its own. The underscores in the name follow the usual Java convention for constants.
An interface works as a container with two kinds of content. Method declarations describe behavior that implementing classes must supply, which is an obligation. Variable declarations describe fixed values that implementing classes receive, which is a gift. Keeping these two effects separate in your mind is the key to reading interfaces correctly.
Tracing Where a Broken Promise Shows Up
When a program that uses interfaces fails, the most useful question is where the result first departed from what the interface promised. Start from the interface declaration and walk forward. Ask whether each declared method has a matching implementation in the class, and whether each constant is being used rather than redefined. The place where that comparison first fails is usually the place to look.
The failure is caught at the comparison step, before the program runs. The point of divergence is the missing stroke method. Anything that appears wrong later in the program may only be a consequence of that early mismatch, so the first failing comparison is the line to examine.
Why a Superclass Needs an Empty Method
Suppose you are building a drawing program with rectangles, ovals, and rounded rectangles. Each knows how to paint itself through its own redraw() method. All of these shapes share a common superclass, which we can call Shape, and the design question is what redraw() should do inside Shape itself.
Whenever a particular shape must draw itself, the redraw() method belonging to that shape's own class is the one that runs. The redraw() inside Shape is never the one drawing a rectangle or an oval. That raises the puzzle: if Shape's version will not really be used, what should it contain?
The honest answer is to leave the body empty. Shape stands for the general notion of a shape, and there is no real way to draw a general notion. Only specific shapes can actually be drawn. Leaving the body blank is therefore not laziness; it reflects the fact that no sensible drawing instructions exist at this level.
But the method cannot simply vanish. Other code in Shape, such as the setColor() method, may call redraw(). A program may also hold a variable declared as Shape and call redraw() on it. The compiler checks these calls against the declared type, not against the object stored there. If Shape had no redraw() at all, those calls would be rejected. So the method must be declared in Shape even though its body does nothing.
Abstract Classes and Their Subclasses
There is never a good reason to build an actual Shape object, because a plain shape with no particular form cannot do anything useful. Programs do, however, need variables whose type is Shape. Such a variable can refer to a rectangle, an oval, or any other specific shape, and calls made through it always reach an object from one of Shape's subclasses.
Shape is therefore an abstract class. It records what every shape has in common while the concrete details live in the subclasses. The idea is stated to the compiler by adding the modifier abstract to the class definition and to the method definition. That modifier makes the abstractness visible in the code so the compiler can enforce the rules that go with it.
public abstract class Shape {
public abstract void redraw();
public void setColor() {
// shared behavior for all shapes
}
}- 1Line 1 declares Shape as an abstract class.
- 2Line 2 declares redraw as an abstract method. It ends in a semicolon instead of a block of code.
- 3Lines 4 to 6 show a concrete method that calls and subclasses can use directly.
- The abstract modifier on the class means no Shape object can be created with new.
- The abstract modifier on redraw means the method has a declaration but no body.
setColoris an ordinary method with a body, which subclasses inherit.
Reading the figure, the top node can never be built directly, while each lower node can. An abstract method declared in the top node must therefore be given a body in each lower node before any object of that lower type can be created and used. This is the point where the abstract declaration becomes concrete behavior.
Declaring an Abstract Method
An abstract method has a particular shape of its own. Where an ordinary method would have a block of code giving its implementation, an abstract method has only a semicolon in that place. The method is declared, so calls to it are legal, but no implementation is supplied at that level of the class hierarchy.
The responsibility does not disappear when the body is omitted. It moves downward. Every concrete subclass of the abstract class must provide an implementation for each abstract method it inherits. The abstract class declares that the operation exists; each concrete subclass says how it works.
Abstract Versus Concrete: What Can Be Built
A class that is not abstract is called concrete. Concrete classes are the ones from which objects can be created. In the shape example, Rectangle, Oval, and RoundRect are concrete classes. You can create objects of any of them, and those objects are the ones that actually get drawn.
| Feature | Abstract class (Shape) | Concrete class (Rectangle) |
|---|---|---|
| Can new create an object? | No | Yes |
| Role | Shared outline of common properties | Supplies everything needed for a working object |
| Abstract methods | May declare them with no body | Must give a body to every inherited abstract method |
| Used as | Declared type of variables | Actual object behind the variable |
Abstract and concrete classes sit at different levels of the hierarchy.
Tracing a New Triangle Subclass
To see the rules applied, imagine a new kind of shape is added to the drawing program: a triangle. The programmer creates a Triangle class that extends Shape. Because Shape declares redraw() as abstract, Triangle is obliged to supply a redraw() implementation before it can be a concrete class. Until then, the program will not accept an attempt to create a Triangle object.
The call s.redraw() runs the redraw body defined in Triangle, because the object is a Triangle even though the variable is declared as Shape.Tracing the Triangle Program
A programmer writes a Triangle class extending Shape and omits redraw. Where does the program stop?
- 1Read the superclass
Shape declares redraw as abstract, so it promises that every concrete subclass will supply a body.
- 2Check the subclass
Triangle inherits the abstract redraw but has no body for it, so it is not yet concrete.
- 3Attempt construction
An attempt to create new Triangle is rejected, because only concrete classes can be instantiated.
- 4Add the body
Once Triangle supplies redraw, it becomes concrete and objects of Triangle can be created and used through Shape variables.
The first failing point is the missing redraw body in Triangle, which is where the program diverges from the abstract class's promise.
Mistakes Beginners Make with Interfaces and Abstract Classes
Common mistake Writing a body for an interface method
What it looks likevoid stroke(Graphics g) { } inside an interfaceWhy it failsAn interface declares methods with no implementations; the body belongs to the implementing class.
Do this insteadWrite void stroke(Graphics g); and put the body in each implementing class.
Common mistake Assuming an interface method without modifiers is not public
Why it failsInterface methods are always public and abstract, even when those keywords are omitted.
Do this insteadRead void stroke(Graphics g); inside an interface as public abstract void stroke(Graphics g);.
Common mistake Trying to construct an abstract class
What it looks likeShape s = new Shape();Why it failsAn abstract class exists only as a basis for subclasses and is not used to construct objects.
Do this insteadConstruct a concrete subclass such as new Rectangle(), and store it in a Shape variable if needed.
Common mistake Deleting an abstract method from the superclass to avoid writing a body
Why it failsCalls through a superclass-typed variable are checked against the declared type, so the method must exist in the superclass.
Do this insteadKeep the abstract declaration in the superclass and supply bodies in the concrete subclasses.
Common mistake Forgetting that a class implementing an interface must define every method the interface specifies
Practice: Predict the Compile Result
A class Circle extends an abstract class Shape that declares public abstract void redraw(). Circle declares no redraw method. Write down whether new Circle() can be compiled, and state which class is responsible for the missing body.
Hints
- Ask whether Circle is abstract or concrete.
- Remember that every concrete subclass must implement each inherited abstract method.
Add a constant named PIXELS_PER_INCH with the value 96 to an interface named Display. Then write one class that implements Display and uses the constant without redefining it.
Hints
- Interface variables are public static final by rule, so you do not need to write those modifiers.
- The implementing class uses the name directly.
Key Takeaways
- A Java interface is a reserved word that introduces instance method declarations with no implementations; an implementing class must provide a body for every method the interface specifies.
- Interface methods are always public and abstract, and interface variables are always public static final, so those modifiers may be omitted.
- An abstract class cannot be used to construct objects; it declares shared properties and abstract methods that every concrete subclass must implement.
- An abstract method is declared with the abstract modifier and ends in a semicolon, and the compiler checks calls against the declared type, which is why the declaration must exist in the superclass.