Objects and References
Understanding Object References
When you create an object in Java, the variable doesn't contain the object itself—it contains a reference to the object's location in memory. Think of it like a GPS coordinate that points to where your robot is parked in the garage. The coordinate isn't the robot, but it tells you exactly where to find it.
Creating Object References:
public class FRCRobot {
private String teamName;
private int teamNumber;
private double batteryLevel;
public FRCRobot(String name, int number) {
this.teamName = name;
this.teamNumber = number;
this.batteryLevel = 100.0;
}
public void useBattery(double amount) {
this.batteryLevel -= amount;
if (this.batteryLevel < 0) {
this.batteryLevel = 0;
}
}
public double getBatteryLevel() {
return this.batteryLevel;
}
public String toString() {
return teamName + " (Team " + teamNumber + ") - Battery: " +
String.format("%.1f", batteryLevel) + "%";
}
}
// When you create an object, you get a reference to it
FRCRobot robot = new FRCRobot("Lightning Bot", 12345);
System.out.println(robot); // Lightning Bot (Team 12345) - Battery: 100.0%Reference Assignment Copies the Reference
When you assign one object variable to another, you're not creating a new object—you're copying the reference. Both variables now point to the same object in memory. This is like giving someone else the GPS coordinates to your robot; now both of you can find and control the same robot.
Reference Assignment Example:
FRCRobot robot1 = new FRCRobot("Thunder Bot", 54321);
System.out.println("Original: " + robot1);
// This copies the REFERENCE, not the object
FRCRobot robot2 = robot1;
// Both variables point to the same object!
robot2.useBattery(25.0); // Use battery through robot2
System.out.println("robot1: " + robot1); // Shows 75% battery
System.out.println("robot2: " + robot2); // Shows 75% battery
// They're the same object, so changes affect both variables
System.out.println("Same object? " + (robot1 == robot2)); // trueThe null Reference
A reference variable can be set to
null, which means it doesn't point to any object. It's like having a GPS coordinate that points to nothing—there's no robot there. Trying to use a null reference will cause a NullPointerException, one of the most common errors in Java programming.Working with null References:
FRCRobot robot = new FRCRobot("Storm Bot", 98765);
System.out.println(robot); // Works fine
// Set the reference to null
robot = null;
System.out.println(robot); // Prints: null
// This will cause a NullPointerException!
// robot.useBattery(10.0); // [ERROR] Don't do this!
// Always check for null before using an object
if (robot != null) {
robot.useBattery(10.0);
System.out.println("Battery used successfully");
} else {
System.out.println("Robot reference is null - cannot use battery");
}
// Safe way to create a new robot
robot = new FRCRobot("Phoenix Bot", 11111);
System.out.println("New robot created: " + robot);NullPointerException Prevention:
Essential Safety Checks:
- Always Check: Use if (object != null) before calling methods
- Initialize Variables: Give object variables initial values when possible
- Defensive Programming: Validate parameters in methods that receive objects
- Read Error Messages: NullPointerException tells you which line caused the error
- Use Debugging: Print object values to see which ones are null
Objects as Method Parameters
Objects can be passed as parameters to methods, just like primitive values. Since objects are passed by reference, the method receives a copy of the reference, not a copy of the object. This means the method can modify the original object.
Objects as Parameters:
public class RobotMaintenance {
// Method that takes a robot as a parameter
public static void performMaintenance(FRCRobot robot) {
if (robot == null) {
System.out.println("[ERROR] Cannot perform maintenance on null robot");
return;
}
System.out.println("[MAINTENANCE] Performing maintenance on: " + robot);
// Simulate maintenance - restore battery to full
robot = new FRCRobot("Maintained Bot", 0); // This creates a NEW object
// The original robot is unchanged because we changed the local reference
System.out.println("[OK] Maintenance complete");
}
// Better maintenance method that actually modifies the robot
public static void rechargeBattery(FRCRobot robot) {
if (robot == null) {
System.out.println("[ERROR] Cannot recharge null robot");
return;
}
System.out.println("🔋 Recharging: " + robot);
// This modifies the original object by calling its methods
// We can't directly set batteryLevel because it's private
// But we can call methods that modify the object's state
System.out.println("[OK] Battery recharged (simulated)");
}
// Method that checks robot battery and recommends action
public static void checkBatteryStatus(FRCRobot robot) {
if (robot == null) {
System.out.println("[ERROR] Cannot check battery on null robot");
return;
}
double battery = robot.getBatteryLevel();
System.out.printf("🔋 Battery level: %.1f%%\n", battery);
if (battery < 20) {
System.out.println("[WARNING] LOW BATTERY - Charge immediately!");
} else if (battery < 50) {
System.out.println("⚡ Consider charging soon");
} else {
System.out.println("[OK] Battery level is good");
}
}
}
// Usage examples:
FRCRobot competitionBot = new FRCRobot("Competition Bot", 12345);
competitionBot.useBattery(60.0); // Use 60% battery
RobotMaintenance.checkBatteryStatus(competitionBot);
RobotMaintenance.rechargeBattery(competitionBot);
RobotMaintenance.performMaintenance(competitionBot);
System.out.println("Final robot state: " + competitionBot);Objects as Return Values
Methods can also return objects. This is useful for creating factory methods, cloning objects, or building new objects based on existing ones. The method returns a reference to the object, which can then be assigned to a variable.
Methods Returning Objects:
public class RobotFactory {
private String manufacturer;
private int robotsBuilt;
public RobotFactory(String manufacturer) {
this.manufacturer = manufacturer;
this.robotsBuilt = 0;
}
// Method that returns a new robot object
public FRCRobot buildRobot(String teamName, int teamNumber) {
this.robotsBuilt++;
System.out.println("[FACTORY] Building robot #" + robotsBuilt + " for " + teamName);
// Create and return a new robot
FRCRobot newRobot = new FRCRobot(teamName, teamNumber);
return newRobot;
}
// Method that creates a copy of an existing robot
public FRCRobot cloneRobot(FRCRobot original) {
if (original == null) {
System.out.println("[ERROR] Cannot clone null robot");
return null;
}
System.out.println("[ROBOT] Cloning robot: " + original);
// Create a new robot with similar properties
// Note: We can't access private fields directly, so we use available methods
FRCRobot clone = new FRCRobot("Clone Bot", 99999);
// In a real implementation, you'd copy all the properties
return clone;
}
// Method that returns a robot with specific configuration
public FRCRobot buildCompetitionRobot(String teamName, int teamNumber) {
FRCRobot robot = this.buildRobot(teamName, teamNumber);
// Perform competition-specific setup
System.out.println("⚙️ Configuring for competition...");
return robot;
}
public int getRobotsBuilt() {
return this.robotsBuilt;
}
}
// Usage examples:
RobotFactory factory = new RobotFactory("FRC Robotics Inc.");
// Create new robots using factory methods
FRCRobot robot1 = factory.buildRobot("Lightning Bolts", 12345);
FRCRobot robot2 = factory.buildCompetitionRobot("Thunder Cats", 54321);
FRCRobot robot3 = factory.cloneRobot(robot1);
System.out.println("\n📊 Factory Status:");
System.out.println("Robots built: " + factory.getRobotsBuilt());
System.out.println("Robot 1: " + robot1);
System.out.println("Robot 2: " + robot2);
System.out.println("Robot 3: " + robot3);Object Equality and the equals() Method
By default, Java compares objects using reference equality (==), which checks if two variables point to the same object in memory. However, you often want to compare objects based on their content. This is where the
equals() method comes in. You can override this method to define what makes two objects 'equal' based on their properties.Implementing equals() Method:
public class FRCRobot {
private String teamName;
private int teamNumber;
private double batteryLevel;
public FRCRobot(String name, int number) {
this.teamName = name;
this.teamNumber = number;
this.batteryLevel = 100.0;
}
// Override the equals method to compare robot content
@Override
public boolean equals(Object compared) {
// Check if they're the same object in memory
if (this == compared) {
return true;
}
// Check if the compared object is null
if (compared == null) {
return false;
}
// Check if the compared object is the right type
if (!(compared instanceof FRCRobot)) {
return false;
}
// Cast to FRCRobot so we can access its properties
FRCRobot other = (FRCRobot) compared;
// Compare the important properties
// Two robots are equal if they have the same team name and number
return this.teamName.equals(other.teamName) &&
this.teamNumber == other.teamNumber;
}
// Other methods...
public void useBattery(double amount) {
this.batteryLevel -= amount;
if (this.batteryLevel < 0) {
this.batteryLevel = 0;
}
}
public String toString() {
return teamName + " (Team " + teamNumber + ") - Battery: " +
String.format("%.1f", batteryLevel) + "%";
}
}
// Testing object equality:
FRCRobot robot1 = new FRCRobot("Lightning Bolts", 12345);
FRCRobot robot2 = new FRCRobot("Lightning Bolts", 12345); // Same team
FRCRobot robot3 = new FRCRobot("Thunder Cats", 54321); // Different team
System.out.println("Reference equality (==):");
System.out.println("robot1 == robot2: " + (robot1 == robot2)); // false (different objects)
System.out.println("robot1 == robot1: " + (robot1 == robot1)); // true (same object)
System.out.println("\nContent equality (equals()):");
System.out.println("robot1.equals(robot2): " + robot1.equals(robot2)); // true (same content)
System.out.println("robot1.equals(robot3): " + robot1.equals(robot3)); // false (different content)
System.out.println("robot1.equals(null): " + robot1.equals(null)); // false (null check)
// Even if battery levels are different, they're still the same team
robot2.useBattery(50.0);
System.out.println("\nAfter using battery:");
System.out.println("robot1: " + robot1);
System.out.println("robot2: " + robot2);
System.out.println("Still equal? " + robot1.equals(robot2)); // true (we ignore battery in equals)Object Equality and Collections
The
equals() method is crucial when working with collections like ArrayList. Methods like contains(), indexOf(), and remove() use the equals() method to find objects in the collection. Without a proper equals() implementation, these methods won't work as expected.Objects in Collections:
import java.util.ArrayList;
public class TeamRoster {
public static void main(String[] args) {
ArrayList<FRCRobot> robots = new ArrayList<>();
// Create some robots
FRCRobot robot1 = new FRCRobot("Lightning Bolts", 12345);
FRCRobot robot2 = new FRCRobot("Thunder Cats", 54321);
FRCRobot robot3 = new FRCRobot("Storm Surge", 98765);
// Add robots to the roster
robots.add(robot1);
robots.add(robot2);
robots.add(robot3);
System.out.println("[LIST] Team Roster:");
for (int i = 0; i < robots.size(); i++) {
System.out.println((i + 1) + ". " + robots.get(i));
}
// Test contains() method - this uses equals()
FRCRobot searchRobot = new FRCRobot("Lightning Bolts", 12345);
if (robots.contains(searchRobot)) {
System.out.println("\n[OK] Found Lightning Bolts in roster!");
} else {
System.out.println("\n[ERROR] Lightning Bolts not found in roster");
}
// Test indexOf() method
int index = robots.indexOf(searchRobot);
if (index >= 0) {
System.out.println("Lightning Bolts is at position: " + (index + 1));
}
// Test with a robot not in the list
FRCRobot unknownRobot = new FRCRobot("Mystery Bot", 00000);
if (robots.contains(unknownRobot)) {
System.out.println("Found Mystery Bot");
} else {
System.out.println("[ERROR] Mystery Bot is not in the roster");
}
// Remove a robot using equals()
boolean removed = robots.remove(searchRobot);
if (removed) {
System.out.println("\n🗑️ Removed Lightning Bolts from roster");
System.out.println("Updated roster size: " + robots.size());
}
// Show that the original robot1 is still in memory
System.out.println("\nOriginal robot1 still exists: " + robot1);
System.out.println("Are they the same object? " + (robot1 == searchRobot)); // false
System.out.println("Are they equal? " + robot1.equals(searchRobot)); // true
}
}Try It Yourself:
Practice with Objects and References
- Create a Sensor class with equals() method that compares sensor type and ID
- Build a Robot class that can be safely cloned with all its sensor references
- Design a Competition class that manages teams and handles null robot references safely
- Create a method that finds robots with low battery levels in a team roster
Test your understanding of object references, null handling, and object equality: