Java Trainer

πŸŽ“ Java Learning Module

The Blueprint & The Building: Classes and Objects in Java

πŸ‘‹ Meet Your Java Trainer!

Hi! I'm Remsey, your Java instructor. Ready to master Classes and Objects together? This is where real OOP starts. πŸš€

🎧 Listen to the Audio Version

Prefer to learn by listening? Hit play below and watch the audio come to life!

70%
0:00 / 0:00

Alright, let's talk about something that's at the absolute heart of Java β€” Classes and Objects.

Think of it this way. You want to build a fleet of custom cars. πŸš—

You don't build each car from scratch β€” you make a blueprint. That blueprint describes what every car should have: a colour, a brand, a number of doors, and the ability to drive and honk.

In Java, that blueprint is a Class. Each actual car you build from it is an Object.

One blueprint. Infinite cars. That's the power of OOP β€” Object-Oriented Programming.

What is a Class?

A class is a template β€” it defines the properties (fields) and behaviours (methods) that every object of that type will have. But by itself, a class doesn't do anything. It just sits there, waiting to be used.

β˜• Car.java β€” The Blueprint
public class Car {
    // Fields (properties)
    String brand;
    String colour;
    int numberOfDoors;

    // Method (behaviour)
    public void drive() {
        System.out.println("πŸš— The " + colour + " " + brand + " is driving!");
    }

    public void honk() {
        System.out.println("πŸ“£ Beep beep!");
    }
}

That's your blueprint. Now let's actually build some cars.

What is an Object?

An object is a specific instance of a class. You create it using the new keyword. Each object gets its own copy of the fields, so they can have totally different values.

πŸ”¨ Main.java β€” Building Objects
public class Main {
    public static void main(String[] args) {
        // Create two Car objects from the same blueprint
        Car myCar = new Car();
        myCar.brand = "Tesla";
        myCar.colour = "red";
        myCar.numberOfDoors = 4;

        Car friendsCar = new Car();
        friendsCar.brand = "BMW";
        friendsCar.colour = "blue";
        friendsCar.numberOfDoors = 2;

        myCar.drive();
        friendsCar.drive();
        myCar.honk();
    }
}
πŸ“€ Expected Output:
πŸš— The red Tesla is driving!
πŸš— The blue BMW is driving!
πŸ“£ Beep beep!

Same blueprint. Two totally different cars. That's objects in action. 🎯

Constructors β€” The Car Factory Worker

Right now, we're setting each field manually after creating the object. Tedious, right? Java has a smarter way: the constructor.

A constructor is a special method that runs automatically when you create a new object. It lets you set everything up in one go β€” like a factory worker who assembles the whole car as it rolls off the production line.

🏭 Car.java β€” With Constructor
public class Car {
    String brand;
    String colour;
    int numberOfDoors;

    // Constructor β€” same name as the class, no return type
    public Car(String brand, String colour, int numberOfDoors) {
        this.brand = brand;
        this.colour = colour;
        this.numberOfDoors = numberOfDoors;
    }

    public void drive() {
        System.out.println("πŸš— The " + colour + " " + brand + " is driving!");
    }

    public void honk() {
        System.out.println("πŸ“£ Beep beep!");
    }
}

class Main {
    public static void main(String[] args) {
        Car myCar = new Car("Tesla", "red", 4);
        Car friendsCar = new Car("BMW", "blue", 2);

        myCar.drive();
        friendsCar.drive();
        System.out.println("Doors on my car: " + myCar.numberOfDoors);
    }
}
πŸ“€ Expected Output:
πŸš— The red Tesla is driving!
πŸš— The blue BMW is driving!
Doors on my car: 4

Notice the this keyword? That's how a constructor refers to the object being created β€” distinguishing the field (this.brand) from the parameter (brand). Smart, right?

Encapsulation β€” The Vault Lock πŸ”’

Right now our fields are fully public. Anyone can waltz in and set myCar.numberOfDoors = -999. That's chaos. Java has a concept called encapsulation: hide your data and provide controlled access via getters and setters.

πŸ”’ BankAccount.java β€” Encapsulation in Action
public class BankAccount {
    private String owner;
    private double balance;

    public BankAccount(String owner, double initialBalance) {
        this.owner = owner;
        this.balance = initialBalance;
    }

    // Getter β€” read-only access
    public double getBalance() {
        return balance;
    }

    // Controlled setter β€” validates before changing
    public void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            System.out.println("βœ… Deposited €" + amount + ". New balance: €" + balance);
        } else {
            System.out.println("❌ Invalid deposit amount!");
        }
    }

    public void withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
            System.out.println("πŸ’Έ Withdrew €" + amount + ". New balance: €" + balance);
        } else {
            System.out.println("❌ Insufficient funds or invalid amount!");
        }
    }
}

class Main {
    public static void main(String[] args) {
        BankAccount account = new BankAccount("Remsey", 1000.0);
        System.out.println("πŸ’° Balance: €" + account.getBalance());
        account.deposit(250.0);
        account.withdraw(80.0);
        account.withdraw(5000.0); // This should fail
    }
}
πŸ“€ Expected Output:
πŸ’° Balance: €1000.0
βœ… Deposited €250.0. New balance: €1250.0
πŸ’Έ Withdrew €80.0. New balance: €1170.0
❌ Insufficient funds or invalid amount!

The private keyword means nobody can touch balance directly. They have to go through your methods β€” and your methods enforce the rules. That's encapsulation: data with a bodyguard. πŸ’ͺ

The toString() Method β€” Give Your Object a Voice

By default, if you print an object in Java you get something hideous like Car@1a2b3c4d. Not exactly useful.

Override toString() to give your object a human-readable description. Java calls this automatically whenever you print the object.

πŸ—£οΈ Person.java β€” toString Override
public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() { return name; }
    public int getAge() { return age; }

    // Override toString so printing the object looks nice
    @Override
    public String toString() {
        return "πŸ‘€ Person{" + "name='" + name + "', age=" + age + "}";
    }
}

class Main {
    public static void main(String[] args) {
        Person p1 = new Person("Remsey", 30);
        Person p2 = new Person("Layla", 25);

        System.out.println(p1);
        System.out.println(p2);
        System.out.println("Hi, my name is " + p1.getName() + "!");
    }
}
πŸ“€ Expected Output:
πŸ‘€ Person{name='Remsey', age=30}
πŸ‘€ Person{name='Layla', age=25}
Hi, my name is Remsey!

🧩 Mini-Challenge

You've got the blueprint. Now build something yourself. Below is a partial Dog class β€” your job is to complete the constructor and add a fetch() method!

πŸ’ͺ Challenge β€” Complete the Dog Class
public class Dog {
    private String name;
    private String breed;

    // TODO: Add a constructor that sets name and breed

    public void bark() {
        System.out.println("πŸ• " + name + " says: Woof woof!");
    }

    // TODO: Add a fetch() method that prints "[name] fetches the ball and brings it back!"

    // TODO: Override toString() to print: "Dog{name='...', breed='...'}"
}

class Main {
    public static void main(String[] args) {
        Dog dog = new Dog("Max", "Labrador");
        dog.bark();
        dog.fetch(); // Uncomment once you've added the method
        System.out.println(dog);
    }
}

πŸ’ͺ Practice Exercises

Test your understanding with these quick exercises! Try to solve them on your own first.

πŸŽ“ Exercise 1: The Student Class

Task: Create a Student class with fields name, studentId, and grade (0–10). Add a constructor, a study() method, a getGrade() getter, and a toString(). Create two students and print them.

πŸ’‘ Hints
  • Make grade a private double
  • The study() method can print a fun message using the student's name
  • Format toString() like: Student{name='...', id='...', grade=...}
βœ… Solution
πŸŽ“ Exercise 1 Solution
public class StudentDemo {

    static class Student {
        private String name;
        private String studentId;
        private double grade;

        public Student(String name, String studentId, double grade) {
            this.name = name;
            this.studentId = studentId;
            this.grade = grade;
        }

        public double getGrade() { return grade; }

        public void study() {
            System.out.println("πŸ“š " + name + " is hitting the books hard!");
        }

        @Override
        public String toString() {
            return "Student{name='" + name + "', id='" + studentId + "', grade=" + grade + "}";
        }
    }

    public static void main(String[] args) {
        Student s1 = new Student("Remsey", "S001", 8.5);
        Student s2 = new Student("Layla", "S002", 9.2);

        s1.study();
        s2.study();
        System.out.println(s1);
        System.out.println(s2);
    }
}

πŸ›’ Exercise 2: Shopping Cart Item

Task: Create a Product class with name, price, and quantity. Add a constructor, a getTotalPrice() method that returns price * quantity, and a toString(). Create three products and print each one's total price.

πŸ’‘ Hints
  • Use private double price and private int quantity
  • getTotalPrice() is a simple multiplication β€” no setter needed
  • Format total with a currency symbol in your print statement
βœ… Solution
πŸ›’ Exercise 2 Solution
public class ShopDemo {

    static class Product {
        private String name;
        private double price;
        private int quantity;

        public Product(String name, double price, int quantity) {
            this.name = name;
            this.price = price;
            this.quantity = quantity;
        }

        public double getTotalPrice() {
            return price * quantity;
        }

        @Override
        public String toString() {
            return "πŸ›οΈ " + name + " x" + quantity + " @ €" + price + " = €" + getTotalPrice();
        }
    }

    public static void main(String[] args) {
        Product coffee = new Product("Coffee", 3.50, 4);
        Product book = new Product("Java Book", 39.99, 1);
        Product headphones = new Product("Headphones", 79.95, 2);

        System.out.println(coffee);
        System.out.println(book);
        System.out.println(headphones);
    }
}

πŸ”’ Exercise 3: The Click Counter

Task: Create a Counter class with a private count field (starts at 0). Add methods increment(), decrement(), reset(), and getCount(). Make sure count never goes below zero. Create two counters and test all methods.

πŸ’‘ Hints
  • Use a guard in decrement(): only subtract if count > 0
  • reset() simply sets count back to 0
  • Give the counter a name in the constructor for nicer output
βœ… Solution
πŸ”’ Exercise 3 Solution
public class CounterDemo {

    static class Counter {
        private String name;
        private int count = 0;

        public Counter(String name) {
            this.name = name;
        }

        public void increment() {
            count++;
            System.out.println("βž• " + name + " count: " + count);
        }

        public void decrement() {
            if (count > 0) {
                count--;
                System.out.println("βž– " + name + " count: " + count);
            } else {
                System.out.println("⚠️ " + name + " is already at zero!");
            }
        }

        public void reset() {
            count = 0;
            System.out.println("πŸ”„ " + name + " reset to 0");
        }

        public int getCount() { return count; }
    }

    public static void main(String[] args) {
        Counter likes = new Counter("Likes");
        Counter errors = new Counter("Errors");

        likes.increment();
        likes.increment();
        likes.increment();
        likes.decrement();

        errors.increment();
        errors.decrement();
        errors.decrement(); // Should warn: already at zero
        errors.reset();

        System.out.println("Final likes: " + likes.getCount());
        System.out.println("Final errors: " + errors.getCount());
    }
}

πŸ’‘ Pro Tip: Try solving these exercises without looking at the solutions first! It's the best way to learn. If you get stuck, check the hints before peeking at the solution.

πŸš€ Ready for the Next Challenge?

Continue your Java journey with Interfaces β€” the contract pattern!

Next Module: Interfaces β†’