Constructors
A constructor is the code that runs the moment an object is born. Every new TalonFX(0), every new SwerveModule(…), every new IntakeSubsystem() calls a constructor. Understanding constructors means understanding exactly what state an object starts in — and why startup order matters on a robot.
By the end of this lesson, you will:
- Write a constructor with the correct syntax — matching class name, no return type
- Distinguish between a default constructor and a parameterized constructor
- Use
this()to chain constructors and avoid duplicating initialization logic - Use
this.fieldNameto disambiguate when a parameter name shadows a field name - Explain why hardware initialization belongs in the constructor, not in a separate
init()method
What a Constructor Is
A constructor is a special method that runs automatically when new ClassName(…) is called. Its job is to put the object into a valid, usable initial state — assigning fields their starting values, creating the hardware objects the subsystem needs, and performing any one-time configuration. A constructor can never be called manually after the object exists; it runs exactly once, at birth.
Three things make constructors syntactically different from regular methods: they have the same name as the class, they have no return type (not even void), and they are called only through new.
Constructor Anatomy
Click each part of the constructor below to understand what it does.
Three Constructor Patterns
A default constructor takes no parameters. If you don't write any constructor at all, Java generates an invisible no-argument constructor that sets all fields to their defaults (0, false, null). As soon as you write any constructor yourself, Java's automatic one disappears.
For subsystems where all configuration lives in Constants.java, a no-argument constructor is appropriate — the constructor reads the constants directly rather than receiving them as parameters.
A parameterized constructor accepts arguments that customize the object at creation time. This makes the class reusable — the same SwerveModule class can represent any corner of the drivetrain because the CAN IDs are passed in rather than hardcoded.
When a parameter name matches a field name, use this.fieldName to refer to the field. this is a reference to the current object.
Constructor chaining lets one constructor call another using this(…) as the first statement. This avoids duplicating initialization logic when you want multiple constructors — a "convenience" constructor delegates to the full one.
This is the same delegation pattern from Unit 2 Lesson 6's method overloading — the shorter form calls the full form, keeping the logic in exactly one place.
Hardware Initialization in Constructors
A common pattern in beginner FRC code is a separate init() method that the programmer calls after construction. This creates a window where the object exists but isn't ready to use — a partially-constructed object that will throw a NullPointerException if anyone calls a method before calling init().
The rule: when new returns, the object must be in a fully valid state. Every field that will ever be used must be initialized in the constructor. This guarantee is what makes method calls on the object safe without checking for null first.
The most common constructor-related bug I see in code review is a private TalonFX motor; field with no initializer and no constructor assignment, combined with methods that call motor.set(…). The code compiles. The robot enables. The first button press throws a NullPointerException that disables the roboRIO. The Driver Station shows a mysterious disconnect. Teams spend hours checking wiring before someone looks at the stack trace. Fully initializing objects in the constructor prevents this entire class of bug.
The this Keyword
Inside a constructor or method, this is a reference to the current object — the specific instance the code is running on. It has two uses that appear constantly in FRC code:
Some teams avoid the this.field = param ambiguity entirely by naming parameters differently: int driveMotorId as the parameter, driveId as the field. This makes assignment unambiguous: driveId = driveMotorId;. Both approaches are valid — the important thing is that the direction is always field ← parameter, never the reverse.
🔌 System Check
- Every hardware field must be assigned in the constructor. If a field is declared but never assigned in the constructor, calling any method that uses it throws
NullPointerExceptionat runtime. There are no compiler warnings for this. - No two-phase construction. Avoid
init()methods that must be called afternew. Put all initialization in the constructor. If setup is complex, call private helper methods from the constructor — but complete it before the constructor returns. - Hardware constructors in
robotInit()or subsystem constructors, never in periodic. Callingnew TalonFX(0)insideteleopPeriodic()creates a new object every 20ms. The old object loses its configuration and the CAN bus floods with repeated initialization messages. - When chaining constructors,
this()must be the first statement. The Java compiler enforces this. Putting anything beforethis()in a constructor is a compile error.
Knowledge Check
private TalonFX motor; as a field but never assigns it in any constructor. What happens at runtime when a method calls motor.set(0.5)?public SwerveModule(int driveId) { this(driveId, 1, 2); motor.set(0); }. What is wrong with this?SwerveModule constructor (accepting drive, steer, and encoder IDs) produce better code than four separate classes — FrontLeftModule, FrontRightModule, etc. — each with hardcoded IDs?Build a Fully Initialized Subsystem
- Take the
ClimberSubsystemfrom Lesson 1's practice prompt. If it has any fields that aren't initialized in the constructor, fix that now. Verify: afternew ClimberSubsystem()returns, every field should be non-null and the object should be immediately usable. - Add a second constructor that accepts the CAN IDs as parameters, allowing the class to be instantiated with either default IDs (from Constants) or custom IDs. Use
this()constructor chaining so the initialization logic lives in exactly one place. - Introduce a deliberate bug: remove the motor initialization from the constructor but leave the method that calls
motor.set(). Run the code and record the exact exception message. Then fix the bug and confirm the exception disappears. - Add a private
configureMotor()helper method that applies current limits and neutral mode to the motor. Call it from the constructor. Verify the constructor is still single-phase: the object is fully ready whennewreturns. - Bonus: Look at WPILib's source code on GitHub. Find the constructor for
edu.wpi.first.wpilibj.XboxController. What parameters does it take? What does it initialize? Does it call any superclass constructor withsuper()? (Lesson 5 coverssuper().)