Abstract Classes and Methods
A Class That Shouldn't Be Instantiated
Every example so far could build a plain RobotPart — Lesson 17.3 even wrote new RobotPart("Generic"). But on a real robot there's no such thing as "just a robot part": every part is an intake, a shooter, a climber. And RobotPart's stop() only prints a message, while every real part has to stop its own hardware in its own way. What the design really wants to say is "RobotPart is only a starting point — every real part must be a subclass, and every subclass must write its own stop()." Java says exactly that with the keyword abstract.
Abstract Classes
Writing abstract in the class declaration makes it an abstract class: a class that can be extended, but never instantiated with new. Here's RobotPart from Lesson 17.1 as an abstract class, with stop() turned into an abstract method:
public abstract class RobotPart
{
private String name;
public RobotPart(String name) { this.name = name; }
public String getName() { return name; }
public void log(String msg) { System.out.println("[" + name + "] " + msg); }
public abstract void stop(); // no body: every subclass writes its own
}
Trying to build one directly is now a compile error:
// ERROR: RobotPart is abstract; cannot be instantiated
RobotPart generic = new RobotPart("Generic");
A class that can be instantiated — every class you've written until now — is called a concrete class.
Abstract Methods
An abstract method is declared with abstract, has a signature, and ends in a semicolon instead of a body: public abstract void stop(); says "every RobotPart has a stop() method" without saying what it does. A class that declares an abstract method must itself be marked abstract — otherwise it doesn't compile.
Concrete Subclasses Must Fill In Every Abstract Method
A concrete subclass must provide a body for every abstract method it inherits. Writing that body is called implementing the method — it uses the same syntax as overriding (Lesson 18.1), including @Override (Lesson 17.4):
public class Intake extends RobotPart
{
public Intake(String name) { super(name); }
@Override
public void stop() { log("rollers off"); }
}
If Intake left stop() out, the compiler would reject it: Intake is not abstract and does not override abstract method stop() in RobotPart. The only other option is for the subclass to be declared abstract too, passing the job down to its subclasses.
What an Abstract Class Can Still Have
abstract removes only the ability to call new on the class itself. Everything else still works:
- Fields —
RobotPartstill has its privatename. - Constructors —
RobotPart(String name)still exists and still runs for everyIntake, throughsuper(name)(Lesson 17.2). You just can't call it withnew RobotPart(...). - Concrete methods —
getName()andlog()have bodies, and every subclass inherits them unchanged. - Use as a type —
RobotPartis still a perfectly good variable, parameter, array, or collection type (Lesson 17.3):RobotPart part = new Intake("Front");andRobotPart[] parts = { new Intake("Front"), new Climber("Left") };both compile. Every object they hold is some concrete subclass, so every one of them really has astop().
Abstract Classes in WPILib
WPILib uses the same tool. MotorSafety (in org.wpilib.hardware.motor) is an abstract class that declares public abstract void stopMotor();, and PWMMotorController, the shared parent of WPILib's PWM motor controller classes, is abstract too. Robot code never writes new PWMMotorController(...) — it constructs one of the specific controller classes that extend it, each of which inherits the shared code.
Looking Ahead: Interfaces
Ch.19 introduces interfaces, a related tool: a type that lists methods a class promises to have, but that has no fields holding object state and no constructors, and that a class can implements several of at once. Ch.19 compares the two directly. The short version: reach for an abstract class when the related classes share real state and code (like RobotPart's name and log()), and an interface when they only share a set of methods.
The rest of this course's RobotPart examples, starting in Ch.18, go back to the concrete RobotPart from Lesson 17.1, whose stop() has a body — Ch.18's lessons override and extend that body.
Common Pitfalls
- Trying to instantiate an abstract class.
new RobotPart("Generic")doesn't compile onceRobotPartis abstract — build a concrete subclass instead, and store it in aRobotPartvariable if you like. - Giving an abstract method a body, or leaving the semicolon off.
public abstract void stop() { }doesn't compile — an abstract method is a signature followed by;, with no braces at all. - Forgetting to implement an abstract method in a concrete subclass. Every abstract method the subclass inherits needs a body, or the subclass must itself be declared
abstract. - Thinking an abstract class can't have constructors or fields. It can have both; its constructor runs through
super(...)from each subclass.
Key Takeaways
- An
abstractclass can be extended but never instantiated withnew; a class that can be instantiated is concrete. - An abstract method has a signature and a semicolon but no body; a class that declares one must itself be
abstract. - A concrete subclass must implement every inherited abstract method (same syntax as overriding, with
@Override), or be declaredabstractitself. - Abstract classes still have fields, constructors (run through
super(...)), concrete methods, and can be used as variable, parameter, and collection types. - WPILib uses abstract classes too (
MotorSafety,PWMMotorController); Ch.19's interfaces are the related tool for sharing methods without shared state.
Authored for this course (new lesson from the 2026-09 content audit; no csawesome-2026 source).