Course Content

Classes and Objects in Java: The Blueprint and Reality of OOP

Introduction: From Concept to Reality

Imagine you're an architect designing houses. You create a blueprint that defines what a house should look like—its rooms, doors, windows, and layout. This blueprint is like a class in Java. When you actually build a house based on that blueprint, you create an object—a real, tangible instance you can live in.

Classes and Objects form the very foundation of Object-Oriented Programming (OOP) in Java. They encapsulate the principles of abstraction, encapsulation, and modularity that make Java such a powerful language for building complex, maintainable systems.

What is a Class? The Blueprint

A class is a template or blueprint for creating objects. It defines:

  1. Attributes/Properties (Data → What an object knows)

  2. Methods/Behaviors (Functions → What an object does)

Anatomy of a Class

java
// Class Definition - The Blueprint
public class Car {
    // 1. Attributes/Properties/Fields (State)
    private String brand;
    private String model;
    private int year;
    private double price;
    private boolean isRunning;
    
    // 2. Constructor (Special method to initialize objects)
    public Car(String brand, String model, int year, double price) {
        this.brand = brand;
        this.model = model;
        this.year = year;
        this.price = price;
        this.isRunning = false; // Default value
    }
    
    // 3. Methods/Behaviors (What the object can do)
    public void startEngine() {
        isRunning = true;
        System.out.println(brand + " " + model + " engine started.");
    }
    
    public void stopEngine() {
        isRunning = false;
        System.out.println(brand + " " + model + " engine stopped.");
    }
    
    public void accelerate(int speedIncrease) {
        if (isRunning) {
            System.out.println("Accelerating by " + speedIncrease + " km/h");
        } else {
            System.out.println("Start the engine first!");
        }
    }
    
    // 4. Getter Methods (Accessors)
    public String getBrand() {
        return brand;
    }
    
    public String getModel() {
        return model;
    }
    
    public double getPrice() {
        return price;
    }
    
    // 5. Setter Methods (Mutators)
    public void setPrice(double newPrice) {
        if (newPrice > 0) {
            this.price = newPrice;
        }
    }
    
    // 6. Utility Method
    public void displayInfo() {
        System.out.println("Brand: " + brand);
        System.out.println("Model: " + model);
        System.out.println("Year: " + year);
        System.out.println("Price: $" + price);
        System.out.println("Status: " + (isRunning ? "Running" : "Stopped"));
    }
}

What is an Object? The Instance

An object is an instance of a class—a concrete realization of the blueprint.

java
public class CarDemo {
    public static void main(String[] args) {
        // Creating objects (instances) of the Car class
        
        // Object 1: myCar (Instance 1)
        Car myCar = new Car("Toyota", "Camry", 2023, 30000);
        
        // Object 2: dreamCar (Instance 2)
        Car dreamCar = new Car("Tesla", "Model S", 2024, 89990);
        
        // Each object has its own separate state
        myCar.displayInfo();
        // Output: Brand: Toyota, Model: Camry, Year: 2023, Price: $30000
        
        dreamCar.displayInfo();
        // Output: Brand: Tesla, Model: Model S, Year: 2024, Price: $89990
        
        // Objects can perform actions
        myCar.startEngine();     // Toyota Camry engine started.
        myCar.accelerate(20);    // Accelerating by 20 km/h
        
        dreamCar.startEngine();  // Tesla Model S engine started.
        dreamCar.accelerate(50); // Accelerating by 50 km/h
    }
}

The Four Pillars of OOP in Action

1. Encapsulation: Data Hiding

Encapsulation bundles data (attributes) and methods that operate on that data within a single unit (class), while hiding internal details.

java
public class BankAccount {
    // Private data - hidden from outside world
    private String accountNumber;
    private String accountHolder;
    private double balance;
    private String password;
    
    // Public interface - controlled access
    public BankAccount(String holder, String pwd, double initialDeposit) {
        this.accountNumber = generateAccountNumber();
        this.accountHolder = holder;
        this.password = pwd;
        this.balance = initialDeposit;
    }
    
    // Methods provide controlled access to private data
    public void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            System.out.println("Deposited: $" + amount);
        }
    }
    
    public boolean withdraw(double amount, String pwd) {
        if (authenticate(pwd) && amount > 0 && amount <= balance) {
            balance -= amount;
            System.out.println("Withdrawn: $" + amount);
            return true;
        }
        return false;
    }
    
    public double getBalance(String pwd) {
        if (authenticate(pwd)) {
            return balance;
        }
        return -1; // Error code
    }
    
    private boolean authenticate(String pwd) {
        return this.password.equals(pwd);
    }
    
    private String generateAccountNumber() {
        return "ACC" + System.currentTimeMillis();
    }
}

2. Inheritance: IS-A Relationship

Inheritance allows a class to acquire properties and behaviors of another class.

java
// Parent/Super Class
public class Animal {
    protected String name;
    protected int age;
    
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public void eat() {
        System.out.println(name + " is eating.");
    }
    
    public void sleep() {
        System.out.println(name + " is sleeping.");
    }
    
    public void makeSound() {
        System.out.println("Animal makes a sound");
    }
}

// Child/Sub Class 1
public class Dog extends Animal {
    private String breed;
    
    public Dog(String name, int age, String breed) {
        super(name, age); // Call parent constructor
        this.breed = breed;
    }
    
    // Method Overriding (Polymorphism)
    @Override
    public void makeSound() {
        System.out.println(name + " says: Woof! Woof!");
    }
    
    // Additional method specific to Dog
    public void fetch() {
        System.out.println(name + " is fetching the ball!");
    }
}

// Child/Sub Class 2
public class Cat extends Animal {
    private int lives = 9;
    
    public Cat(String name, int age) {
        super(name, age);
    }
    
    @Override
    public void makeSound() {
        System.out.println(name + " says: Meow!");
    }
    
    public void climb() {
        System.out.println(name + " is climbing a tree!");
    }
    
    public void loseLife() {
        if (lives > 0) {
            lives--;
            System.out.println(name + " has " + lives + " lives left");
        }
    }
}

3. Polymorphism: Many Forms

Polymorphism allows objects of different classes to be treated as objects of a common super class.

java
public class PolymorphismDemo {
    public static void main(String[] args) {
        // Polymorphism in action
        Animal[] animals = new Animal[3];
        
        animals[0] = new Animal("Generic Animal", 5);
        animals[1] = new Dog("Buddy", 3, "Golden Retriever");
        animals[2] = new Cat("Whiskers", 2);
        
        // Same method call, different behaviors
        for (Animal animal : animals) {
            animal.makeSound(); // Dynamic method dispatch
        }
        // Output:
        // Animal makes a sound
        // Buddy says: Woof! Woof!
        // Whiskers says: Meow!
        
        // Type checking and casting
        for (Animal animal : animals) {
            if (animal instanceof Dog) {
                Dog dog = (Dog) animal; // Downcasting
                dog.fetch();
            } else if (animal instanceof Cat) {
                Cat cat = (Cat) animal; // Downcasting
                cat.climb();
            }
        }
    }
}

4. Abstraction: Hiding Complexity

Abstraction focuses on essential qualities rather than specific details.

java
// Abstract Class (Partial abstraction)
abstract public class Shape {
    protected String color;
    
    public Shape(String color) {
        this.color = color;
    }
    
    // Abstract method (no implementation)
    abstract public double calculateArea();
    
    // Concrete method
    public void displayColor() {
        System.out.println("Color: " + color);
    }
}

// Concrete Class 1
public class Circle extends Shape {
    private double radius;
    
    public Circle(String color, double radius) {
        super(color);
        this.radius = radius;
    }
    
    @Override
    public double calculateArea() {
        return Math.PI * radius * radius;
    }
    
    public double calculateCircumference() {
        return 2 * Math.PI * radius;
    }
}

// Concrete Class 2
public class Rectangle extends Shape {
    private double length;
    private double width;
    
    public Rectangle(String color, double length, double width) {
        super(color);
        this.length = length;
        this.width = width;
    }
    
    @Override
    public double calculateArea() {
        return length * width;
    }
    
    public double calculatePerimeter() {
        return 2 * (length + width);
    }
}

Constructors: Object Initialization

Constructors are special methods that initialize new objects.

java
public class Student {
    private String name;
    private int rollNumber;
    private String course;
    private double grade;
    
    // 1. Default Constructor (No-args)
    public Student() {
        this.name = "Unknown";
        this.rollNumber = 0;
        this.course = "Not Enrolled";
        this.grade = 0.0;
    }
    
    // 2. Parameterized Constructor
    public Student(String name, int rollNumber) {
        this.name = name;
        this.rollNumber = rollNumber;
        this.course = "Computer Science";
        this.grade = 0.0;
    }
    
    // 3. Fully Parameterized Constructor
    public Student(String name, int rollNumber, String course, double grade) {
        this.name = name;
        this.rollNumber = rollNumber;
        this.course = course;
        this.grade = grade;
    }
    
    // 4. Copy Constructor
    public Student(Student other) {
        this.name = other.name;
        this.rollNumber = other.rollNumber;
        this.course = other.course;
        this.grade = other.grade;
    }
    
    // Constructor Chaining using this()
    public Student(String name) {
        this(name, 0, "General Studies", 0.0);
    }
}

The this Keyword: Self-Reference

The this keyword refers to the current object instance.

java
public class Employee {
    private String name;
    private int id;
    private double salary;
    
    // Differentiating instance variables from parameters
    public Employee(String name, int id, double salary) {
        this.name = name;  // this.name = instance variable
        this.id = id;      // id = parameter
        this.salary = salary;
    }
    
    // Using this to call another constructor
    public Employee(String name) {
        this(name, 0, 50000); // Calls the main constructor
    }
    
    // Using this to return current object
    public Employee promote(double raisePercentage) {
        this.salary += this.salary * (raisePercentage / 100);
        return this; // Allows method chaining
    }
    
    // Method chaining example
    public Employee setName(String name) {
        this.name = name;
        return this;
    }
    
    public Employee setSalary(double salary) {
        this.salary = salary;
        return this;
    }
}

// Using method chaining
Employee emp = new Employee("John", 101, 60000);
emp.setName("John Doe").setSalary(75000).promote(10);

Static vs Instance Members

java
public class Counter {
    // Instance variable (unique for each object)
    private int instanceCount = 0;
    
    // Static/Class variable (shared by all objects)
    private static int staticCount = 0;
    
    public Counter() {
        instanceCount++;
        staticCount++;
    }
    
    // Instance method
    public int getInstanceCount() {
        return instanceCount;
    }
    
    // Static method (can be called without creating object)
    public static int getStaticCount() {
        return staticCount;
    }
    
    // Static block (executed when class is loaded)
    static {
        System.out.println("Counter class loaded!");
    }
}

// Usage
public class StaticDemo {
    public static void main(String[] args) {
        // Access static method without creating object
        System.out.println("Initial static count: " + Counter.getStaticCount());
        
        Counter c1 = new Counter();
        Counter c2 = new Counter();
        Counter c3 = new Counter();
        
        // Each object has its own instanceCount
        System.out.println("c1 instance: " + c1.getInstanceCount()); // 1
        System.out.println("c2 instance: " + c2.getInstanceCount()); // 1
        System.out.println("c3 instance: " + c3.getInstanceCount()); // 1
        
        // All share the same staticCount
        System.out.println("Total objects created: " + Counter.getStaticCount()); // 3
    }
}

Real-World Example: E-Commerce System

java
import java.util.ArrayList;
import java.util.Date;

// Product Class
public class Product {
    private String productId;
    private String name;
    private String description;
    private double price;
    private int stockQuantity;
    
    public Product(String id, String name, double price, int quantity) {
        this.productId = id;
        this.name = name;
        this.price = price;
        this.stockQuantity = quantity;
    }
    
    // Getters and setters
    public boolean reduceStock(int quantity) {
        if (quantity <= stockQuantity) {
            stockQuantity -= quantity;
            return true;
        }
        return false;
    }
}

// Customer Class
public class Customer {
    private String customerId;
    private String name;
    private String email;
    private String address;
    private ArrayList<Order> orderHistory;
    
    public Customer(String id, String name, String email) {
        this.customerId = id;
        this.name = name;
        this.email = email;
        this.orderHistory = new ArrayList<>();
    }
    
    public void placeOrder(Order order) {
        orderHistory.add(order);
        System.out.println("Order placed successfully!");
    }
}

// Order Class
public class Order {
    private String orderId;
    private Customer customer;
    private ArrayList<Product> products;
    private Date orderDate;
    private double totalAmount;
    private String status;
    
    public Order(Customer customer) {
        this.orderId = "ORD" + System.currentTimeMillis();
        this.customer = customer;
        this.products = new ArrayList<>();
        this.orderDate = new Date();
        this.status = "Pending";
        this.totalAmount = 0.0;
    }
    
    public void addProduct(Product product, int quantity) {
        if (product.reduceStock(quantity)) {
            products.add(product);
            totalAmount += product.getPrice() * quantity;
            System.out.println("Product added to order");
        }
    }
    
    public void processPayment() {
        this.status = "Paid";
        System.out.println("Payment processed. Total: $" + totalAmount);
    }
}

// Main Application
public class ECommerceApp {
    public static void main(String[] args) {
        // Create products
        Product laptop = new Product("P001", "Laptop", 999.99, 10);
        Product phone = new Product("P002", "Smartphone", 699.99, 25);
        
        // Create customer
        Customer john = new Customer("C001", "John Doe", "john@email.com");
        
        // Create and process order
        Order order = new Order(john);
        order.addProduct(laptop, 1);
        order.addProduct(phone, 2);
        order.processPayment();
        
        john.placeOrder(order);
    }
}

Common Pitfalls and Best Practices

Pitfall 1: Creating Getters/Setters for Everything

java
// ❌ BAD: Exposing everything
public class Employee {
    public String name;
    public double salary;
    public String ssn; // Social Security Number exposed!
}

// ✅ GOOD: Controlled access
public class Employee {
    private String name;
    private double salary;
    private String ssn;
    
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    
    public double getSalary() { return salary; }
    // No setSalary - salary can only be changed through promote()
    
    // No getter for SSN - it shouldn't be exposed
}

Pitfall 2: Not Following Naming Conventions

java
// ❌ BAD
public class student { // Should be Student
    private String NAME; // Should be name
    public void GETINFO() { } // Should be getInfo
}

// ✅ GOOD
public class Student {
    private String name;
    private int rollNumber;
    
    public void displayInfo() { }
    public String getName() { return name; }
}
 
Course Reviews

No reviews yet.