Skip to the content.
Intro Anatomy of a Class Constructors Accessor Methods Mutator Methods Static Variables Game

Unit 5 - Writing Classes P1

AP CSA

  • HINT:
  • Accesor Methods
  • Popcorn Hack #1:
  • Mutators/Setters
  • Lets take a look at an example!
  • Popcorn Hack
  • Static Variables
  • What will we be teaching?

    We will be teaching Unit 5, Writing Classes. We will explore the anatomy of a class, fields, methods, and constructors. We will learn how constructors initialize objects and the different types, how mutators (setters) modify object properties, and how static variables belong to the class rather than any instance. By the end, there will be a solid understanding of how to create and manage objects efficiently in Java

    Unit 5 Topics For Learning:

    • 5.1 Anatomy of a Class
    • 5.2 Constructors
    • 5.4 Accessor Methods
    • 5.5 Mutator
    • 5.7 Static Variables and Methods

    Why do we need to write classes?

    Writing classes in Java is essential because it allows you to organize your code into reusable, modular components. Think of a class as a blueprint for creating objects. Without classes, your code would be cluttered and difficult to manage, especially as projects grow larger. Why not just write all your code in one place? Well, that would make it hard to maintain and update, leading to errors and inefficiency. Classes enable you to encapsulate data and behavior, making your code more flexible, scalable, and easier to troubleshoot. This structured approach is key for building complex, real-world applications.

    Homework Assignment: Constructors, Mutators, Accessors, and Static Variables in Java

    Objective:

    Create a BankAccount class to practice working with constructors, mutators (setters), accessors (getters), and static variables in Java.

    Instructions:

    Class: BankAccount

    • Instance Variables:
      • String accountHolderName
      • double balance
    • Static Variable:
      • static int totalAccounts (tracks the number of accounts created)

    Constructors:

    • Default constructor: Sets accountHolderName to "Unknown" and balance to 0.0.
    • Parameterized constructor: Accepts accountHolderName and balance as parameters.
    • Both constructors should increment totalAccounts.

    Mutator Methods:

    • void setAccountHolderName(String name): Updates the account holder’s name.
    • void deposit(double amount): Adds money to the balance.
    • void withdraw(double amount): Subtracts money from the balance (if funds are available).

    Accessor Methods:

    • String getAccountHolderName(): Returns the account holder’s name.
    • double getBalance(): Returns the account balance.
    • static int getTotalAccounts(): Returns the total number of accounts created.

    Main Program (BankApp):

    • Create three BankAccount objects.
    • Modify account holder names and balances using setters.
    • Print account details using getters.
    • Display the total number of accounts created.

    Example Output:

    Account Holder: Alice  
    Balance: 500.0
    
    Account Holder: Bob  
    Balance: 1000.0
    
    Account Holder: Charlie  
    Balance: 750.0
    
    Total number of accounts created: 3
    

    Submission:

    Submit a Jupyter Notebook file containing your final code.

    Anatomy of a Class

    This notebook will explain the structure of a class in Java, including attributes, methods, and instantiation. It will also include examples and a mini-project that requires fixing broken code.

    Class Anatomy Diagram

    1. Introduction to Classes

    • A class in Java is a blueprint for creating objects. It defines a data structure that includes methods and attributes.
    • Example:
    public class Car {
        // Attributes
        String model;
        int year;
    
        // Method
        void drive() {
            System.out.println("Driving the car.");
        }
    }
    
    

    This Car class has attributes model and year, and a method drive() that prints a message.

    2. Attributes and Methods

    • Attributes (or fields) are variables that belong to an object.
    • Methods are functions that belong to a class.
    • Example:

    public class Person { // Attributes String name; int age;

    // Method
    void greet() {
        System.out.println("Hello, my name is " + name);
    } } In this `Person` class, `name` and `age` are attributes, and `greet()` is a method.
    

    3. Constructor

    • Constructors are special methods used to initialize objects.
    • They have the same name as the class and do not have a return type.
    • Example:
    public class Person {
        String name;
        int age;
    
        // Constructor
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        void greet() {
            System.out.println("Hello, my name is " + name);
        }
    }
    
    

    This Person class includes a constructor to initialize name and age.

    4. Class vs. Instance Variables

    • Instance variables are attributes specific to each object.
    • Class variables (static variables) are shared among all instances of the class.
    • Example:
    public class Car {
        // Class variable
        static int numberOfCars = 0;
    
        // Instance variables
        String model;
        int year;
    
        // Constructor
        public Car(String model, int year) {
            this.model = model;
            this.year = year;
            numberOfCars++;
        }
    }
    
    

    Here, numberOfCars is a class variable that keeps track of how many Car objects have been created.

    5. Mini Project: Fix the Code

    • Below is a class with broken code. The goal is to fix the class so it properly initializes and uses instance variables.
    • Broken code:

    • Task: Debug the Book class so it correctly initializes title and author. Consider how the constructor should be modified.

    public class Book { String title; String author;

    // Broken constructor
    public Book(String title) {
        title = title;
    } }
    
    • Task: Debug the Book class so it correctly initializes title and author. Consider how the constructor should be modified.

    Introduction to Constructors in Java

    What are Constructors?

    In Java, a constructor is a special method used to initialize objects. The constructor is called when an object of a class is created. It has the same name as the class and does not return any value, not even void.

    Key Points:

    • Same name as class: The constructor must have the same name as the class.
    • No return type: Constructors do not return any value.
    • Used to initialize objects: They set initial values for object attributes.

    Types of Constructors

    TypesofConstructors

    1. Default Constructor:

    A constructor that does not accept any parameters. Java provides a default constructor if you don’t define any.

    class Car {
        String brand;
        
        // Default constructor
        Car() {
            brand = "Unknown";
        }
    }
    
    Car myCar = new Car();
    System.out.println(myCar.brand);  // Outputs: Unknown
    
    Unknown
    

    2. Parameterized Constructor:

    A constructor that takes parameters to initialize object attributes with custom values.

    class Car {
        String brand;
    
        // Parameterized constructor
        Car(String b) {
            brand = b;
        }
    }
    
    Car myCar = new Car("Toyota");
    System.out.println(myCar.brand);  // Outputs: Toyota
    
    Toyota
    

    3. Constructor Overloading

    Constructor Overloading

    In Java, you can have more than one constructor in a class. This is known as constructor overloading. Each constructor must have a different parameter list.

    class Car {
        String brand;
        int year;
    
        // Default constructor
        Car() {
            brand = "Unknown";
            year = 0;
        }
    
        // Parameterized constructor
        Car(String b, int y) {
            brand = b;
            year = y;
        }
    }
    Car car1 = new Car();
    Car car2 = new Car("Ford", 2020);
    System.out.println(car1.brand + " " + car1.year);  // Outputs: Unknown 0
    System.out.println(car2.brand + " " + car2.year);  // Outputs: Ford 2020
    
    Unknown 0
    Ford 2020
    

    Constructors Diagram

    Escape Room: Constructor Puzzle

    You’re trapped in a room and the only way out is to unlock a door using your Java constructor knowledge!

    Rules:

    • Each clue is a code snippet related to constructors. Solve the problems to reveal the next clue.
    • Once you complete all tasks, you will receive the “escape” message.

    Clue 1:

    The constructor below is missing a key part. Complete the code so that it runs correctly.

    // CLUE  1 
    
    class Door {
        String lockCode;
    
        // Add the correct constructor here
        Door(String lock) {
            // Constructor body
            lockCode = "1234";
        }
    }
    
    
    Door escapeDoor = new Door("1234");
    System.out.println(escapeDoor.lockCode);  // Should print: 1234
    
    
    1234
    
    //CLUE 2
    
    class Room {
        String name;
        int area;
    
        // Constructor 1
        Room(String name) {
            this.name = "Puzzle Room";
        }
    
        // Constructor 2 (missing)
        Room(String name, int area) {
            this.name = "Puzzle Room";
            this.area = 500;
        }
    }
    
    Room escapeRoom = new Room("Puzzle Room", 500);
    System.out.println("Room: " + escapeRoom.name + ", Area: " + escapeRoom.area);  
    // Should print: Room: Puzzle Room, Area: 500
    
    
    Room: Puzzle Room, Area: 500
    
    //CLUE 3
    class Key {
        String keyType;
    
        // Default constructor (to be completed)
        Key() {
            keyType = "Unknown";
            // Hint: Initialize keyType to a default value, e.g., "Unknown"
        }
    
        // Parameterized constructor
        Key(String keyType) {
            this.keyType = keyType;
        }
    }
    
    Key defaultKey = new Key();
    Key customKey = new Key("Golden Key");
    
    System.out.println("Default Key: " + defaultKey.keyType);  // Should print: Unknown
    System.out.println("Custom Key: " + customKey.keyType);    // Should print: Golden Key
    
    
    Default Key: Unknown
    Custom Key: Golden Key
    
    //CLUE 4
    class Vault {
        String vaultCode;
        boolean isLocked;
    
        // Constructor
        Vault(String code, boolean lockStatus) {
            vaultCode = code;
            isLocked = lockStatus;
        }
    }
    
    Vault secretVault = new Vault("X1Y2Z3", true);
    System.out.println("Vault Code: " + secretVault.vaultCode + ", Is Locked: " + secretVault.isLocked);
    // Should print: Vault Code: X1Y2Z3, Is Locked: true
    
    
    Vault Code: X1Y2Z3, Is Locked: true
    
    //CLUE 5
    class Safe {
        String safeName;
        int capacity;
    
        // Default constructor
        Safe() {
            // Initialize safeName to "Unknown" and capacity to 100
            safeName = "Unknown";
            capacity = 100;
        }
    
        // Parameterized constructor
        Safe(String name, int cap) {
            safeName = name;
            capacity = cap;
        }
    }
    
    Safe defaultSafe = new Safe();
    Safe customSafe = new Safe("Treasure Safe", 1000);
    
    System.out.println(defaultSafe.safeName + " " + defaultSafe.capacity);  // Outputs: Unknown 100
    System.out.println(customSafe.safeName + " " + customSafe.capacity);    // Outputs: Treasure Safe 1000
    
    
    Unknown 100
    Treasure Safe 1000
    
    //CLUE 6
    class Box {
        String color;
        int weight;
    
        // Constructor (with mistake)
        Box(String color, int w) {
            this.color = color;
            weight = w;
        }
    }
    
    Box myBox = new Box("Red", 50);
    System.out.println("Box Color: " + myBox.color + ", Weight: " + myBox.weight);
    // Should print: Box Color: Red, Weight: 50
    
    Box Color: Red, Weight: 50
    
    //FINAL CLUE
    class TreasureChest {
        String chestType;
        int goldCoins;
        boolean isLocked;
    
        // Constructor 1: No parameters (calls Constructor 2 with default values)
        TreasureChest() {
            this("Wooden", 50, true);  // Chaining to Constructor 2 with default values
        }
    
        // Constructor 2: Takes all parameters
        TreasureChest(String type, int coins, boolean locked) {
            chestType = type;
            goldCoins = coins;
            isLocked = locked;
        }
    
        // Constructor 3: Takes only type and coins, defaults 'isLocked' to true
        TreasureChest(String type, int coins) {
            this(type, coins, true);  // Chaining to Constructor 2, passing true for isLocked
        }
    
        // Constructor 4: Takes only the number of coins and defaults type to "Wooden" and isLocked to false
        TreasureChest(int coins) {
            this("Wooden", coins, false);  // Chaining to Constructor 2 with default values
        }
    
        // Print method to check the values
        void printChestInfo() {
            System.out.println("Chest Type: " + chestType + ", Gold Coins: " + goldCoins + ", Is Locked: " + isLocked);
        }
    }
    
    public class EscapeRoom {
        public static void main(String[] args) {
            // Test the different constructors by creating different objects
            TreasureChest chest1 = new TreasureChest();
            TreasureChest chest2 = new TreasureChest("Golden", 100);
            TreasureChest chest3 = new TreasureChest(200);
    
            // Print information to check if everything works correctly
            chest1.printChestInfo();  // Should print: Wooden, 50, true
            chest2.printChestInfo();  // Should print: Golden, 100, true
            chest3.printChestInfo();  // Should print: Wooden, 200, false
    
            // Escape message when code is correctly fixed
            if (chest1 != null && chest2 != null && chest3 != null) {
                System.out.println("You have successfully escaped!");
            }
        }
    }
    

    HINT:

    1. Constructor chaining: You must properly use this() to chain constructors and avoid code duplication.
    2.	Calling another constructor from a constructor: Ensure that each constructor calls the correct constructor with default or passed values.
    3.	Initialize all fields properly: Ensure that every TreasureChest object is initialized with the correct values based on the constructor called.
    

    Accesor Methods

    What is an accessor method?

    • Allow safe access to instance variables
      • Prevents access to variables from outside
    • AKA “get methods” or “getters”
    • If another class or a function needs access to the variable, you use an accessor method

    Example:

    public class snack { 
        private String name; 
        private int calories; 
    
        public Snack() { 
            name ""; 
            calories = 0; 
        }
    
        public Snack (string n, int c) { 
            name = n; 
            calories = c; 
        }
    
        public String getName(){
            return Name; 
        }
    
        public int getCalories() { 
            return calories; 
        }
    }
    
    |       public Snack() { 
    
    invalid method declaration; return type required
    
    
    
    |           name ""; 
    
    not a statement
    
    
    
    |           name ""; 
    
    ';' expected
    
    
    
    |       public Snack (string n, int c) { 
    
    invalid method declaration; return type required
    

    Private Instance Variables:

    private String name; private int calories;

    Default Constructors

    public Snack() { name ""; calories = 0; }

    Overload Constructor

    public Snack (string n, int c) { name = n; calories = c; }

    Accessor Methods

    ` public String getName(){ return Name; }`

    public int getCalories() { return calories; }

    • Return command reciprocate a copy of the instance variable

    Requirements

    • Accessor Methods must be public
    • Return type must match the variable type
      • int = int
      • string = string
      • etc
    • REMEMBER PRINTING A VALUE IS NOT THE SAME AS RETURNING
    • Name appropriately
      • Often is getNameOfVariable
    • No parameters

    Notice how the methods from the example match: public String getName(){ and public int getCalories()

    Accessors Diagram

    Popcorn Hack #1:

    Below is a constructor of a class, write the acccessor methods for all instance variables.

    public class Pet { 
    
        private String name;  // Variable names should start with lowercase
        private String typeOfPet;
        private int age;
    
        public String getName() { 
            return name;  // Return 'name', not 'Name'
        }
    
        public String getTypeOfPet() { 
            return typeOfPet; 
        }
    
        public int getAge() { 
            return age; 
        }
    }
    

    How can we print out all the information about an instance of an object?

    public class SportTester {
        public static void main (string[] args) {
            sport volley = new Sport("volleyball", 12); 
            system.out.println(volley);
        }
    
        public String toString(String sportName, int numPlayers) {
            return "Sport: " + sportName + ", Players: " + numPlayers;
        }
    }
    
    
    /* see what it prints out 
       This is called hash code in hexadecimal form*/
    
    
    |       public static void main (string[] args) {
    
    cannot find symbol
    
      symbol:   class string
    
    
    
    |           sport volley = new Sport("volleyball", 12); 
    
    cannot find symbol
    
      symbol:   class sport
    
    
    
    |           sport volley = new Sport("volleyball", 12); 
    
    cannot find symbol
    
      symbol:   class Sport
    
    
    
    |           system.out.println(volley);
    
    package system does not exist
    

    Mutators/Setters

    Mutators are used to modify the attribute of an object. They are typically public methods to allow external code to modify the object state.

    Naming & Parameters

    Mutators are named in the setBlank syntax where “Blank” is the name of the field you want to modify. Mutators, like other methods in Java, take one or more parameters.

    Return Type

    Since mutators are type void as they do not return a value but rather they modify the object’s state.

    Validation

    Mutators often include validation logic to ensure that the new values are being set within acceptable bounds. An example of validation being used with mutators can be seen with the setSpeed mutator that doesn’t allow negative values.

    Mutators Diagram

    Lets take a look at an example!

    This example discusses showcases some of the most vital use cases for mutators

    // A class representing a Car with attributes like make, model, and speed.
    public class Car {
        private String brand;
        private String model;
        private int speed;
    
        // Constructor to initialize attributes
        public Car(String brand, String model, int speed) {
            this.brand = brand;
            this.model = model;
            if (speed >= 0) {  
                this.speed = speed;
            } else {
                System.out.println("Speed cannot be negative, setting speed to 0.");
                this.speed = 0;
            }
        }
        //Mutators 
        public void setBrand(String brand) {
            this.brand = brand;
        }
        public void setModel(String model) {
            this.model = model;
        }
        public void setSpeed(int speed) {
            if (speed >= 0) { //Validation so speed is not negative
                this.speed = speed;
            } else {
                System.out.println("Speed cannot be negative.");
            }
        }
        // Display car details
        public void displayCarInfo() {
            System.out.println("Brand: " + brand);
            System.out.println("Model: " + model);
            System.out.println("Speed: " + speed + " mph");
        }
    }
    Car myCar = new Car("Honda", "Civic", 100);
    myCar.displayCarInfo();
    
    // Modifying attributes mutators
    myCar.setSpeed(150);
    myCar.setBrand("Rolls Royce");
    myCar.setModel("Phantom");
    myCar.displayCarInfo();
    
    //Testing Validation with invalid value (Should trigger warning)
    myCar.setSpeed(-50); 
    
    Brand: Honda
    Model: Civic
    Speed: 100 mph
    Brand: Rolls Royce
    Model: Phantom
    Speed: 150 mph
    Speed cannot be negative.
    

    Popcorn Hack

    1. Create a Class

    Define a class Person with private fields: String name, int age, and double height. This is done for you.

    2. Create Mutators

    Write mutator methods setName(String name), setAge(int age) (with validation for non-negative age), and setHeight(double height) (with validation for non-negative height).

    3. Write a Constructor

    Create a constructor that initializes name, age, and height with provided values.

    4. Test the Mutators

    In the main method, create a Person object, modify its fields using the mutators, and print the details after each modification.

    public class Person {
        // Step 1: Define private fields
        private String name;
        private int age;
        private double height;
    
        // Step 2: Create mutators (setters) with validation
        public void setName(String name) {
            this.name = name;
        }
    
        public void setAge(int age) {
            if (age >= 0) {  // Validation to ensure non-negative age
                this.age = age;
            } else {
                System.out.println("Age cannot be negative.");
            }
        }
    
        public void setHeight(double height) {
            if (height >= 0) {  // Validation to ensure non-negative height
                this.height = height;
            } else {
                System.out.println("Height cannot be negative.");
            }
        }
    
        // Step 3: Constructor to initialize fields
        public Person(String name, int age, double height) {
            this.name = name;
            setAge(age);  // Using mutator to ensure validation
            setHeight(height);  // Using mutator to ensure validation
        }
    
        // Method to display person details
        public void displayPersonInfo() {
            System.out.println("Name: " + name);
            System.out.println("Age: " + age);
            System.out.println("Height: " + height + " meters");
        }
    }
    public class PersonTester {
        public static void main(String[] args) {
            // Step 4: Create a Person object using constructor
            Person person1 = new Person("Alice", 25, 1.65);
    
            // Display initial details
            System.out.println("Initial Person Details:");
            person1.displayPersonInfo();
    
            // Modify the fields using mutators
            System.out.println("\nModifying Person Details:");
            person1.setName("Bob");
            person1.setAge(30);   // Valid age
            person1.setHeight(1.75);  // Valid height
            person1.displayPersonInfo();
    
            // Test validation by setting an invalid age
            System.out.println("\nTesting Validation:");
            person1.setAge(-5);   // Invalid age, should trigger a warning
            person1.setHeight(-1.8);  // Invalid height, should trigger a warning
            person1.displayPersonInfo();
        }
    }
    
    
    public class Person {
        // Private fields
        private String name;
        private int age;
        private double height;
    
        public Car(String brand, String model, int speed) {
            this.brand = brand;
            this.model = model;
            if (speed >= 0) {  
                this.speed = speed;
            } else {
                System.out.println("Speed cannot be negative, setting speed to 0.");
                this.speed = 0;
            }
        }
        //Mutators 
        public void setBrand(String brand) {
            this.brand = brand;
    }
    }
    
    Car myCar = new Car("Honda", "Civic", 100);
    myCar.displayCarInfo();
    
    // Modifying attributes mutators
    myCar.setSpeed(150);
    myCar.setBrand("Rolls Royce");
    myCar.setModel("Phantom");
    myCar.displayCarInfo();
    
    //Testing Validation with invalid value (Should trigger warning)
    myCar.setSpeed(-50); 
    
    |       public Car(String brand, String model, int speed) {
    
    invalid method declaration; return type required
    

    Static Variables

    This notebook will explain what static variables are, how they differ from instance variables, and provide examples, including a mini-project with broken code to fix.

    1. Introduction to Static Variables

    • Static variables belong to the class rather than any particular instance. They are shared across all instances of the class.
    • Example:
    public class BankAccount {
        // Static variable
        static double interestRate = 0.03;
    
        // Instance variable
        double balance;
    
        // Constructor
        public BankAccount(double balance) {
            this.balance = balance;
        }
    
        // Static method
        static void setInterestRate(double newRate) {
            interestRate = newRate;
        }
    }
    

    In this BankAccount class, interestRate is a static variable shared by all instances, and setInterestRate() is a static method that updates this variable.

    2. Defining Static Variables

    • Static variables are defined using the static keyword and accessed using the class name.
    • Example:
    public class Student {
        // Static variable
        static String schoolName = "XYZ School";
    
        // Instance variable
        String name;
    
        // Constructor
        public Student(String name) {
            this.name = name;
        }
    }
    
    // Accessing static variable
    System.out.println(Student.schoolName);
    

    Here, schoolName is a static variable shared by all Student instances.

    3. Static Methods

    • Static methods can access static variables but cannot access instance variables directly.
    • Example:
    public class BankAccount {
        static double interestRate = 0.03;
    
        static void updateInterestRate(double newRate) {
            interestRate = newRate;
        }
    }
    
    // Using static method
    BankAccount.updateInterestRate(0.04);
    

    The updateInterestRate method updates the static variable interestRate.

    4. Mini Project: Fix the Code

    • Below is a class with broken code. The goal is to fix the class so it correctly implements and accesses static variables and methods.
    • Broken code:
    
    public class Vehicle {
        static int count = 0;
    
        // Constructor
        public Vehicle() {
            count = count + 1;
        }
    
        // Method
        public void displayCount() {
            System.out.println(count);
        }
    }
    
    
    • Task: Debug the Vehicle class to ensure count is properly incremented and displayed. Consider how displayCount() should be modified if count is a static variable.