AdamBots Team 245
Before we start

Sign in

  1. 1Open your phone's camera
  2. 2Point it at the code
  3. 3Tap the link and fill in the form

No phone? Tell a mentor and we'll sign you in.

Today Session 3 · Classes and Objects Rookie Bootcamp · Programming Track
📋 Attendance
forms.gle/os9g31bhyXHY3bPd6
AdamBots Team 245
Rookie Bootcamp · Programming Track · Session 3

Classes &
Objects

One blueprint, as many robot parts as you need

Today's mission

No more mystery words

Last session's Intake.java is back. You can read most of it now.

But some words we said to "just copy for now." They're circled in gold.

Today you learn what every one means.

01

Why objects?

A swerve drive has four identical modules

Without classes, the code gets out of hand

Drivetrain.java0 variables

      
There has to be a better way.
★ Story time
1960sOslo, Norway

Two Norwegians who wanted to simulate the world

The goalAt the Norwegian Computing Center, Ole-Johan Dahl and Kristen Nygaard wanted to simulate real systems: factories, traffic, customers waiting in line.
The ideaDescribe one kind of thing once (a class), then make as many as you want (objects), each with its own data.
1967Their language, Simula 67, introduced classes and objects. Java's classes come straight from that idea.
2001They won the Turing Award, computing's version of the Nobel Prize.
The big idea

The class is the blueprint. Objects are the real things.

CLASS
SwerveModule
Every module has
driveId
angle

One drawing. Says what every module has and does.

new ×4 →
frontLeftobject
driveId
1
angle
0°
frontRightobject
driveId
3
angle
45°
backLeftobject
driveId
5
angle
90°
backRightobject
driveId
7
angle
-30°

Same design. Each object has its own motor ID and its own current angle.

Inside a class

What it knows, and what it does

SwerveModule
Knows fieldsdriveIdanglespeed
Does methodsdrive()setAngle()stop()
Intake
Knows fieldsmotorbeamBreak
Does methodsrun()stop()hasGamePiece()
Fields are variables that belong to the object. Methods are what the object can do.
Surprise

You've been using objects since last session

msg.length()Ask the String object msg how many characters it has
System.out.println("Hi")Ask the screen-printing object System.out to print
motor.setThrottle(0.5)Ask the motor object to spin at half power
The dot means: "this object, please do this."
02

Writing a class

Our example for today

Meet the Battery class

Battery.javaa blueprint
public class Battery {
    String name;
    int year;
    double voltage;

    boolean isMatchReady() {
        return voltage >= 12.0;
    }
}
LINE 1The class name: Battery. Capital first letter, in Battery.java.
FIELDSWhat every battery knows: its name, year and voltage. Declared inside the class, outside any method.
METHODWhat every battery can do: say if it's ready for a match.
NOTEThe method uses the field voltage directly. It's this battery's own voltage.
★ Our team's ruleWe name every battery and check its voltage before every match. 12.0 V or more means it's match-ready.
From blueprint to battery

new builds an object from the class

Main.javauses the blueprint
Battery a = new Battery();
a.name = "2025-A";
a.year = 2025;
a.voltage = 12.8;

System.out.println(a.isMatchReady());
  output
true
TYPEBattery a: a variable named a that holds a Battery. The class is the type.
NEWnew Battery(): build one real battery object from the blueprint.
DOTFill in a's own fields, using the dot.
CALLAsk a whether it's match-ready.
Interactive · object factory

Each object gets its own copy of the fields

CLASS
Battery

name · year · voltage
isMatchReady()

Click a battery's voltage to change it.

Press new Battery() to build one.

Predict, then reveal

Same method, different answers

aBattery
name
"2025-A"
year
2025
voltage
12.8
bBattery
name
"2023-C"
year
2023
voltage
11.8
a.isMatchReady()true
b.isMatchReady()false

Each call uses that object's own voltage.

Compare

Class vs. object

The blueprint

Class

  • Written once, in its own file
  • Capital first letter: Battery
  • Describes fields and methods
  • Exists while you write code
VS
The real thing

Object

  • As many as you want
  • Made with new
  • Lower-case variable: spareBattery
  • Exists while the program runs
Battery is the class. spareBattery is one battery.
Callback to last session

One class per file, and files work together

📁 ex01
.java

Battery.java

public class Battery { ... }

The blueprint

.java

Main.java

public class Main { main ... }

Uses it: new Battery()

Main.java can use Battery without any import, because both files are in the same folder.

That folder is called a package. More in section 7.

★ Today's exercisesUnzip today's pack into C:\bootcamp, then open the C:\bootcamp\session3 folder in WPILib VS Code. Each exercise is its own folder inside it: ex01, ex02... The first line of each file says package ex01;. Leave it alone for now.
▶ Try it · 6 min

Your first class

Open the ex01 folder

  • In Battery.java, add a method describe() that prints the name, year and voltage.
  • In Main.java, build three batteries with new and fill in their fields.
  • Call describe() and isMatchReady() on each one.
  • Stretch: add a method int age(int thisYear).
  example output
2025-A (2025): 12.8 V
  match-ready: true
2024-B (2024): 11.8 V
  match-ready: false
2023-C (2023): 12.6 V
  match-ready: true
★ Hintdescribe() doesn't return anything, so its return type is void. Inside it, just use name, year and voltage.
No more mystery words

Find the class parts

  • The class: Intake
  • Two fields: motor and beamBreak
  • Each one built with new: a motor object and a sensor object
  • Three methods: run, stop, hasGamePiece
03

Constructors

The problem

What if you forget to fill in the fields?

Battery c = new Battery();
System.out.println(c.name);
System.out.println(c.isMatchReady());
  output
null
false
cBattery
name
null
year
0
voltage
0.0

Fields you don't set get default values: 0, 0.0, false, or null for objects.

What if Java made you fill in the important parts when you build it?

Constructor

A constructor sets up each new object

Battery.javawith a constructor
public class Battery {
    String name;
    int year;
    double voltage;

    public Battery(String name, int year, double voltage) {
        this.name = name;
        this.year = year;
        this.voltage = voltage;
    }
    // ...isMatchReady() as before
}
NAMESame name as the class: Battery.
NO TYPENo return type, not even void. That's how Java knows it's a constructor.
JOBCopy the values handed in into this object's fields.
WHENRuns once, automatically, every time you say new.
  now in Main.java
Battery a = new Battery("2025-A", 2025, 12.8);
this

this means "my own"

1 · The call
new Battery("2025-A", 2025, 12.8)
→
2 · Parameters
name"2025-A"
year2025
voltage12.8

Temporary. Gone when the constructor ends.

→
3 · this object's fields
new Batteryobject
this.name
"2025-A"
this.year
2025
this.voltage
12.8

Kept as long as the object lives.

⚠ The classic bugvoltage = voltage; copies the parameter into itself. The field is never set and stays 0.0. Always write this.voltage = voltage;
The error everyone hits

Once you add a constructor, new Battery() stops working

  problems
Main.java:5: error: constructor Battery in class Battery
cannot be applied to given types;
    Battery spare = new Battery();
                    ^
  required: String,int,double
  found:    no arguments
MEANS"Battery's constructor needs three things and you gave it none."
REQUIREDWhat it wants: a String, an int, a double.
FIXnew Battery("Spare", 2024, 12.6)
Read the error: "required" tells you exactly what to hand in.
Constructors on our robot

What if the robot had two intakes?

public class Intake {
    private final PWMSparkMax motor;
    private final DigitalInput beamBreak;

    public Intake(int motorChannel, int sensorChannel) {
        motor = new PWMSparkMax(motorChannel);
        beamBreak = new DigitalInput(sensorChannel);
    }
}
Intake front = new Intake(0, 1);
Intake back  = new Intake(2, 3);

The channel numbers move into the constructor. One class, two separate intakes.

The four-module problem, solved

new SwerveModule(1, 2);
new SwerveModule(3, 4);
new SwerveModule(5, 6);
new SwerveModule(7, 8);

Write the class once. Build it four times with different IDs.

▶ Try it · 5 min

Add a constructor

Open the ex02 folder

  • Run Main.java. Every battery says 0.0 V. Why?
  • Find the bug in Battery's constructor and fix it.
  • In Main.java, add a fourth battery ("2022-D", 2022, 11.9) in one line.
  • Stretch: add a second constructor that takes only a name (year 2026, voltage 12.0).
  before the fix
2025-A: 0.0 V  ready: false
2024-B: 0.0 V  ready: false
2023-C: 0.0 V  ready: false
★ HintLook for a line where a name is assigned to itself.
Break

Stretch!

Back in 10 minutes. Next: arrows, and the most famous crash in Java.

04

References and null

Callback to last session's memory stepper

Every object variable holds an arrow

countint
1

A primitive (int, double, boolean, char...) sits right inside its box.

msgString
Count:space1

A String box holds an arrow.

aBattery
Battery object
name
"2025-A"
voltage
12.8

So does every object variable. The arrow is called a reference.

Interactive · press Step, predict first

Two arrows, one battery

  output
 
MEMORY
Explained at last

== compares arrows. .equals() compares contents.

modeString
auto
from the dashboard
targetString
auto
typed in your code
mode == targetfalse

Same letters, but two different objects in two places. The arrows are different.

mode.equals(target)true

.equals() looks inside and compares the characters.

That's why we said last session: always compare Strings with .equals().
null

null: a box with an arrow to nothing

spareBattery
no object
Battery spare = null;

The variable exists. The battery doesn't.

Object fields you never set start as null too (remember c.name printing null?).

Primitives can't be null. An int always holds a number.

★ Story time
1965London, England

The billion-dollar mistake

1965British computer scientist Tony Hoare added the null reference to a language called ALGOL W, "simply because it was so easy to implement."
DecadesAlmost every language copied it, Java included. Arrows to nothing caused countless crashes, bugs and security holes.
2009At a conference he publicly apologized, calling it his "billion-dollar mistake."
BonusHe also invented Quicksort, one of the most-used ways to sort data in the world.
Even legends make mistakes. The good ones admit it.
Interactive · the most famous crash in Java

The NullPointerException

  output
 
MEMORY
NullPointerExceptions on the robot

It deploys fine. Then it crashes when you enable.

public class Intake extends SubsystemBase {
    private PWMSparkMax motor;   ⟦// no new!⟧

    public void stop() {
        motor.setThrottle(0.0);
    }
}
  driver station console
Unhandled exception: java.lang.NullPointerException:
Cannot invoke "PWMSparkMax.setThrottle(double)"
because "this.motor" is null
  at frc.robot.subsystems.Intake.stop(Intake.java:5)
✓
Build succeeds
✓
Deploy succeeds
✕
Enable: crash, robot code restarts
Rule: every object field gets its new, where it's declared or in the constructor.
▶ Try it · 5 min

Null hunt

Open the ex03 folder

  • Run Main.java. It crashes with a NullPointerException.
  • Read the message: which variable is null? Which file and line?
  • Fix it, run again. A second, sneakier null is waiting.
  • Both fixed? The robot drives and prints "All systems go".
  first crash
Exception in thread "main"
java.lang.NullPointerException:
Cannot invoke "ex03.Motor.setThrottle(double)"
because "this.rightMotor" is null
  at ex03.Drivetrain.drive(Drivetrain.java:15)
  at ex03.Main.main(Main.java:10)
★ Hint for the second oneLook closely at setup(). Is it filling in the field, or making a brand-new variable with the same name?
No more mystery words

Why Intake can't crash with null

  • Both object fields get their new right where they're declared
  • So motor is never null when run() or stop() uses it
  • beamBreak is never null either
05

static vs. instance

Interactive · static means "shared by the whole class"

One clock on the wall, a backpack for everyone

public class Battery {
!!    static int batteriesMade = 0;
    double voltage;

    public Battery(double voltage) {
        this.voltage = voltage;
        batteriesMade++;
    }
}
STATICOne copy, owned by the class. Like the wall clock.
INSTANCEOne per object. Like each student's backpack.
Battery class · staticbatteriesMade0
A mystery from last session, solved

Why is main static?

!!public static void main(String[] args) {

When the program starts, no objects exist yet.

So main has to work without an object. It belongs to the class: static.

Static methods you've already used

Math.max(3, 7) → 7

Math.abs(-0.4) → 0.4

No new Math() needed. You call them on the class name, because they don't need any object's data.

The error everyone hits

"cannot be referenced from a static context"

public static void main(String[] args) {
    ⟦describe()⟧;
}
  problems
error: non-static method describe() cannot be
referenced from a static context
public static void main(String[] args) {
    Battery a = new Battery("2025-A", 2025, 12.8);
    a.describe();
}
TRANSLATION"describe() needs a battery. Which battery? You didn't make one."
FIXMake an object with new, then call the method on it.
Interactive · the tempting wrong fix

Don't "fix" it by making everything static

SwerveModule.javatry both
public class SwerveModule {
    double angle;
}
angle is an instance field

Where static is exactly right

Constants: static final

private static final int kMotorChannel = 0;
private static final int kSensorChannel = 1;
private static final double kIntakeSpeed = 0.75;
◆ Robot projectsMost teams keep these in one file, Constants.java, so every number lives in one place.
STATICOne copy for the class. Every Intake uses the same speed.
FINALCan't change after it's set. Try, and the compiler refuses.
kWPILib style: constants start with k.
▶ Try it · 4 min

Fix it the right way

Open the ex04 folder

  • Main.java has three "static context" errors.
  • Fix each one by making a SwerveModule object and calling the method on it.
  • Do not add the word static to SwerveModule.java.
  • Run it. A built-in check warns you if the modules are secretly sharing an angle.
  when it's right
FL angle: 45.0
FR angle: 90.0
FL is driving at 0.5
CHECK PASSED: each module has its own angle
★ HintSwerveModule fl = new SwerveModule("FL"); then fl.setAngle(45);
Break

Recharge!

Back in 10 minutes. Next: private, packages, and lots of objects.

06

private and public

The problem

If anyone can change a field, anyone can break it

Shooter.javasomeone else's file
// "I'll just make it faster"
motor.speed = ⟦5.0⟧;

A motor only understands -1.0 to 1.0. Nothing stops 5.0 from getting in.

And a teammate's code could change it in the middle of a match.

5.0 ?!
⚡
Interactive · private

private: only this class can touch it

SafeMotor.javaclick to switch
 
speed is private
🔒
0.0
⚡
  compiler
Ready.
The front door

public methods are the safe way in

public class SafeMotor {
    private double speed;

    public void setSpeed(double speed) {
        this.speed = Math.clamp(speed, -1.0, 1.0);
    }

    public double getSpeed() {
        return speed;
    }
}
HIDDENThe field is private. Nobody outside can touch it.
SETTERThe only way to change it. It can clamp, check, or refuse.
GETTERLets others read the value without changing it.
Hide the inside. Offer safe buttons on the outside. This is called encapsulation.
The robot rule of thumb

Fields private, useful methods public

  • Every field in Intake is private
  • run(), stop(), hasGamePiece() are public: other code needs them
  • A helper only this class uses? Make it private too.
▶ Try it · 5 min

Build a SafeMotor

Open the ex05 folder

  • In SafeMotor.java, make speed private.
  • Main.java stops compiling on one line. Read the error, then delete that line: that's the point!
  • Make setSpeed clamp the value to -1.0 to 1.0.
  • Run it until every check says PASS.
  goal
setSpeed(0.5) -> 0.5   PASS
setSpeed(3.0) -> 1.0   PASS
setSpeed(-7.0) -> -1.0   PASS
setSpeed(-0.25) -> -0.25   PASS
★ HintOne line: Math.clamp(speed, -1.0, 1.0). An if / else if works too.
07

Packages and imports

package

A package is a folder

package frc.robot.subsystems;
📁frc
📁robot
📁subsystems
📄Intake.java
Each dot is a folder. The package line must match where the file lives, or it won't compile.
import

import: borrowing a class from another package

package frc.robot.subsystems;

import org.wpilib.drivers.motor.PWMSparkMax;

"I'm using the PWMSparkMax class from WPILib's org.wpilib.drivers.motor package."

  forgot the import?
error: cannot find symbol
  symbol:   class PWMSparkMax
  location: class Intake
PWMSparkMax motor;
💡
Import 'PWMSparkMax' (org.wpilib.drivers.motor)
Create class 'PWMSparkMax'

VS Code's light bulb (Ctrl + .) adds the import for you.

★ Story time
2016March · the internet

Eleven lines that broke the internet

The codeA tiny package called left-pad: about 11 lines that add spaces to the front of a piece of text.
Who used itThousands of JavaScript projects imported it, often without knowing, through other packages they imported.
One dayIts author removed it from npm, the big public library of JavaScript code. Builds failed all over the world, including tools used by major websites.
Modern programs are built from other people's classes. Know what you import.
Interactive · click a file

Tour of a robot project

📁 src/main/java
📁 frc/robot
📁 subsystems
📁 commands
Click a file

Every file is one class, in a folder that matches its package.

08

Many objects: arrays and lists

Arrays · callback to last session's char slots

An array is a row of numbered slots

@@1SwerveModule[] modules = new SwerveModule[4];
@@2modules[0] = new SwerveModule(1, 2);
@@3modules[1] = new SwerveModule(3, 4);
@@3modules[2] = new SwerveModule(5, 6);
@@3modules[3] = new SwerveModule(7, 8);

Four slots, numbered 0 to 3. Each one starts as null.

Last slot is length - 1. modules[4] crashes: ArrayIndexOutOfBoundsException.

modulesSwerveModule[]
null
0
null
1
null
2
null
3
(1, 2)
(3, 4)
(5, 6)
(7, 8)
for-each loop

One loop talks to every object

for (SwerveModule m : modules) {
    m.stop();
}

Read it as: "for each module m in modules, stop it."

★ The four-module problem, fully solvedOne class, one array, one loop. Fix a bug once and all four modules get the fix.
modules[0]m.stop() ✓
modules[1]m.stop() ✓
modules[2]m.stop() ✓
modules[3]m.stop() ✓
ArrayList

ArrayList: a list that grows

import java.util.ArrayList;

ArrayList<Battery> cart = new ArrayList<>();
cart.add(new Battery("2025-A", 2025, 12.8));
cart.add(new Battery("2024-B", 2024, 12.3));

System.out.println(cart.size());      // 2
System.out.println(cart.get(0).name); // 2025-A
<Battery>"A list of Batteries only." Anything else won't compile.
ADDGrows as you add. Arrays are a fixed size; lists aren't.
SIZE / GETHow many, and the one at a position. Still numbered from 0.
⚠ Off by one, againcart.get(cart.size()) crashes. The last one is size() - 1.
▶ Try it · 6 min

The battery cart

Open the ex06 folder

  • Make an ArrayList<Battery> called cart.
  • Add the five batteries listed in the comments.
  • Loop over the cart and print each battery's status.
  • Count how many are match-ready and print the total.
  • Stretch: find and print the battery with the highest voltage.
  example output
2025-A  12.8 V  ready
2025-B  11.8 V  charge me
2024-A  12.7 V  ready
2024-B  11.9 V  charge me
2023-A  12.5 V  ready
3 of 5 batteries are match-ready
★ HintMake an int ready = 0; before the loop and add 1 inside an if.
09

A first look at extends

★ Story time
1970sXerox PARC, California

A computer language for kids

The nameAlan Kay coined the term "object-oriented programming." He pictured objects like living cells: each does its own job and sends messages to the others.
SmalltalkHis team built Smalltalk, a language he hoped kids could use to build their own programs.
DynabookHe also sketched the Dynabook: a thin, portable computer for children. That was 1972, decades before tablets existed.
The ideas you're learning today were designed with students in mind.
extends

extends means "is a kind of"

SubsystemBase written by WPILib
periodic()setDefaultCommand(...)... and more
is a kind of
Intake written by us
run()stop()hasGamePiece()

+ everything above, for free

public class Intake extends SubsystemBase {

    @Override
    public void periodic() {
        // runs every 20 ms
    }
}

@Override: "I'm replacing a method I inherited." The robot calls periodic() every 20 ms (the loop from our first session).

The details come in a later session on command-based code. For now: an Intake is a Subsystem.

10

Putting it together

The missing piece

Where does the Intake object come from?

  • RobotContainer imports our Intake class
  • and builds one Intake object with new
  • plus a controller object for the driver
  • Hold A: the intake's run method. Let go: stop.

Class written in Intake.java → object built in RobotContainer → methods called every loop.

Mission complete

No more mystery words

Click a layer to turn it on or off.

Structure Data Control Methods Objects (new!)
▶ Try it · 10 min · in pairs

Build a subsystem from scratch

Open the ex07 folder

  • Motor.java and BeamBreak.java are fake robot parts. Don't change them.
  • In Intake.java: two private fields (a Motor and a BeamBreak).
  • A constructor that takes the two channel numbers and builds both with new.
  • run(): spin at 0.75 unless there's a game piece, then stop. stop(). hasGamePiece().
  • Run Main.java: a 50-loop simulated match checks your Intake.
  goal
loop  0: motor 0.75  piece: false
loop 19: motor 0.75  piece: false
loop 20: motor 0.0   piece: true
PASS  motor runs before the piece
PASS  motor stops when the piece arrives
PASS  hasGamePiece() is true at the end
3 / 3 checks passed
★ HintThe beam is blocked when a piece is inside, so hasGamePiece() returns !beamBreak.get(). Same as Intake.java.
Recap

Five things to remember

01

A class is a blueprint. new builds an object.

02

Constructors set up new objects. Use this.

03

Object variables hold arrows. null means no object.

04

static belongs to the class. Never use it to silence errors.

05

Fields private, useful methods public.

Quick check · tap an answer

How much do you remember?

1 · What does new do?

The class is the blueprint; new builds one real object from it

2 · b = a; b.voltage = 11.9; Now a.voltage is...

a and b are two arrows to the same battery

3 · Why is main static?

main runs before any object is built, so it belongs to the class

4 · What's wrong with voltage = voltage; in a constructor?

It copies the parameter into itself. Use this.voltage = voltage;
AdamBots Team 245
Up next · Session 4

Our
Tools

VS Code, WPILib, Git and GitHub, build and deploy. Finish the exercise pack before then.

Press ? for keyboard help · T for contents

Contents T or Esc to close

Keyboard & mouse ? or Esc to close

→SpacePgDnEnterNext step or slide (also: click the right half of the screen, or a clicker)
←PgUpBackspaceBack (also: click the left half, or right-click)
Home EndFirst slide / last slide
12… then EnterJump to a slide number
TContents: jump to any slide (or the ☰ button, top-left)
NShow or hide speaker notes
FFullscreen on / off
?This help
EscClose notes, contents, help or a photo
On interactive slides, clicking bulbs, switches, buttons, sliders, photos and quiz answers works the piece instead of changing slides.