PYnative

Python Programming

  • Learn Python ▼
    • Python Tutorials
    • Python Basics
    • Python Interview Q&As
  • Exercises ▼
    • Python Exercises
    • C++ Exercises
    • C Programming Exercises
    • Java Exercises
    • C# Exercises
  • Quizzes
  • Online Compilers▼
    • Online Python Code Editor
    • Online C Compiler
    • Online C++ Compiler
    • Online Java Compiler
    • Online C# Compiler
Home » Java Exercises » Java OOP Exercises: 40 Coding Problems with Solutions

Java OOP Exercises: 40 Coding Problems with Solutions

Updated on: July 9, 2026 | Leave a Comment

This collection of 40 Java OOP exercises covers every core object-oriented concept, from basic encapsulation to abstract classes, interfaces, and composition versus aggregation.

What You’ll Practice

  • Encapsulation & Constructors: Private fields, constructor overloading and chaining, and the copy constructor pattern.
  • Inheritance & Polymorphism: super(), multilevel and hierarchical inheritance, method overriding, variable shadowing, and runtime polymorphism through dynamic method dispatch.
  • Abstraction: Abstract classes and methods, interfaces, multiple interface implementation, default methods, and combining extends with implements.
  • Class Design: Method overloading, toString() overriding, static fields and counters, final variables and methods, and enums used as a state machine.
  • Object Relationships: Aggregation versus composition, illustrated with a university department and a computer’s internal components.

Each exercise includes a Problem Statement, Purpose, Hint, and a Solution with Explanation, so you understand exactly which OOP principle each piece of code demonstrates.

  • Also, See: Java Exercises with over 20+ topic-wise sets and 575+ coding questions to practice.
  • Practice questions using our Online Java Compiler
+ Table of Contents (40 Exercises)

Table of contents

  • Exercise 1: Book Repository (Encapsulation)
  • Exercise 2: Rectangle Dimensions (Object and Class)
  • Exercise 3: Secure Bank Account
  • Exercise 4: Employee Payroll Basics
  • Exercise 5: Student Grading System
  • Exercise 6: Car Dashboard
  • Exercise 7: Inventory Item
  • Exercise 8: Time Validation
  • Exercise 9: Circle Initialization
  • Exercise 10: Patient Admission (Constructor Chaining)
  • Exercise 11: Point Duplicator (Copy Constructor)
  • Exercise 12: Complex Number Addition
  • Exercise 13: Smartphone Configurator (Method Chaining)
  • Exercise 14: Flight Tracker
  • Exercise 15: Vehicle Customization (Basic Inheritance)
  • Exercise 16: Multilevel Living (Multilevel Inheritance)
  • Exercise 17: Shape Coloring (Hierarchical Inheritance)
  • Exercise 18: Polite Person (Method Overriding with super)
  • Exercise 19: Variable Shadowing Resolution
  • Exercise 20: Manager Salary Calculation
  • Exercise 21: Grocery Stock (Perishable Goods)
  • Exercise 22: Tiered Banking
  • Exercise 23: Universal Calculator (Method Overloading)
  • Exercise 24: Search Directory (Method Overloading)
  • Exercise 25: Animal Chorus (Runtime Polymorphism)
  • Exercise 26: Dynamic Method Dispatch
  • Exercise 27: Payroll Calculation with Overriding
  • Exercise 28: String Representation Override
  • Exercise 29: Abstract Classes
  • Exercise 30: Appliance Control
  • Exercise 31: Flyable Contract
  • Exercise 32: Hybrid Machines (Multiple Interfaces)
  • Exercise 33: Tax Compliance (Abstract + Interface)
  • Exercise 34: Default Methods in Interfaces
  • Exercise 35: E-Commerce Payment Gateway
  • Exercise 36: Instance Counter (Static Keyword)
  • Exercise 37: Immutable Configuration (Final Keyword)
  • Exercise 38: The University Setup (Aggregation)
  • Exercise 39: The Desktop System (Composition)
  • Exercise 40: State Machine (Enums with OOP)

Exercise 1: Book Repository (Encapsulation)

Problem Statement: Create a Book class with private attributes for title, author, and price. Implement getters and setters, ensuring that the price cannot be set to a negative value.

Purpose: This exercise helps you practice encapsulation by keeping fields private and controlling access through getters and setters, while also validating input inside a setter to protect object state.

Given Input: Book book = new Book("Java Basics", "James Gosling", 45.0); book.setPrice(-10);

Expected Output: Invalid price. Price not changed. Current price: 45.0

▼ Hint
  • Declare title, author, and price as private fields.
  • Write a constructor that accepts and assigns all three values.
  • In setPrice(), check if the incoming value is negative before assigning it.
  • If the value is negative, print a message and leave the existing price unchanged.
▼ Solution & Explanation
class Book {
    private String title;
    private String author;
    private double price;

    public Book(String title, String author, double price) {
        this.title = title;
        this.author = author;
        this.price = price;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        if (price < 0) {
            System.out.println("Invalid price. Price not changed. Current price: " + this.price);
        } else {
            this.price = price;
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Book book = new Book("Java Basics", "James Gosling", 45.0);
        book.setPrice(-10);
    }
}Code language: Java (java)

Explanation:

  • private String title, author; private double price;: These fields are hidden from outside classes, forcing all access to go through getters and setters.
  • public Book(...): The constructor initializes a new Book object with the given title, author, and price.
  • if (price < 0): Validates the input before assignment. If the check fails, the method rejects the update and keeps the current price.
  • this.price = price: Assigns the parameter value to the instance field only when the value passes validation.

Exercise 2: Rectangle Dimensions (Object and Class)

Problem Statement: Design a Rectangle class with length and width attributes. Include methods to calculate and return the area and perimeter.

Purpose: This exercise reinforces how to model a real-world object as a class, storing its properties as fields and exposing behavior through methods that operate on those fields.

Given Input: Rectangle rect = new Rectangle(10, 5);

Area = 50.0
Perimeter = 30.0
▼ Hint

Area is length * width, and perimeter is 2 * (length + width). Write each formula inside its own method and return the result.

▼ Solution & Explanation
class Rectangle {
    private double length;
    private double width;

    public Rectangle(double length, double width) {
        this.length = length;
        this.width = width;
    }

    public double getArea() {
        return length * width;
    }

    public double getPerimeter() {
        return 2 * (length + width);
    }
}

public class Main {
    public static void main(String[] args) {
        Rectangle rect = new Rectangle(10, 5);
        System.out.println("Area = " + rect.getArea());
        System.out.println("Perimeter = " + rect.getPerimeter());
    }
}Code language: Java (java)

Explanation:

  • private double length, width: Stores the rectangle’s dimensions as instance fields.
  • getArea(): Multiplies length and width and returns the result as a double.
  • getPerimeter(): Adds length and width, then multiplies the sum by 2 to get the total boundary length.

Exercise 3: Secure Bank Account

Problem Statement: Create a BankAccount class with a private balance. Implement safe deposit(double amount) and withdraw(double amount) methods that validate inputs and prevent overdrafts.

Purpose: This exercise builds on encapsulation by protecting a sensitive field, balance, from invalid changes and teaches how to guard against illegal state transitions such as negative deposits or overdrafts.

Given Input: BankAccount acc = new BankAccount(100); acc.deposit(50); acc.withdraw(200);

Deposited: 50.0
New balance: 150.0
Insufficient funds. Withdrawal denied.
▼ Hint
  • In deposit(), reject the amount if it is less than or equal to zero.
  • In withdraw(), reject the amount if it exceeds the current balance.
  • Only update balance after the validation check passes.
▼ Solution & Explanation
class BankAccount {
    private double balance;

    public BankAccount(double balance) {
        this.balance = balance;
    }

    public void deposit(double amount) {
        if (amount <= 0) {
            System.out.println("Invalid deposit amount.");
            return;
        }
        balance += amount;
        System.out.println("Deposited: " + amount);
        System.out.println("New balance: " + balance);
    }

    public void withdraw(double amount) {
        if (amount > balance) {
            System.out.println("Insufficient funds. Withdrawal denied.");
            return;
        }
        balance -= amount;
        System.out.println("Withdrawn: " + amount);
    }
}

public class Main {
    public static void main(String[] args) {
        BankAccount acc = new BankAccount(100);
        acc.deposit(50);
        acc.withdraw(200);
    }
}Code language: Java (java)

Explanation:

  • private double balance: Keeps the account balance hidden so it can only change through controlled methods.
  • if (amount <= 0): Blocks deposits of zero or negative amounts before they can affect the balance.
  • if (amount > balance): Prevents withdrawing more money than is available, avoiding a negative balance.
  • balance += amount / balance -= amount: Updates the balance only after the corresponding validation check succeeds.

Exercise 4: Employee Payroll Basics

Problem Statement: Create an Employee class with an id, name, and salary. Add a method raiseSalary(double percentage) that modifies the salary attribute.

Purpose: This exercise practices writing a method that mutates an object’s own state based on a calculation, a common pattern in business and payroll style applications.

Given Input: Employee emp = new Employee(101, "Priya", 50000); emp.raiseSalary(10);

Expected Output: Updated salary for Priya: 55000.0

▼ Hint

Calculate the raise amount as salary * (percentage / 100), then add it to the existing salary before printing the updated value.

▼ Solution & Explanation
class Employee {
    private int id;
    private String name;
    private double salary;

    public Employee(int id, String name, double salary) {
        this.id = id;
        this.name = name;
        this.salary = salary;
    }

    public void raiseSalary(double percentage) {
        salary += salary * (percentage / 100);
        System.out.println("Updated salary for " + name + ": " + salary);
    }
}

public class Main {
    public static void main(String[] args) {
        Employee emp = new Employee(101, "Priya", 50000);
        emp.raiseSalary(10);
    }
}Code language: Java (java)

Explanation:

  • private int id; private String name; private double salary;: Stores the employee’s core details as private fields.
  • salary * (percentage / 100): Calculates the raise amount as a percentage of the current salary.
  • salary += ...: Adds the calculated raise directly to the existing salary field, updating the object’s state.

Exercise 5: Student Grading System

Problem Statement: Create a Student class containing an array of numerical marks. Implement a method to calculate the average mark and another to return a pass or fail status string.

Purpose: This exercise combines arrays with class design, showing how a class can hold a collection of values and expose calculated results and derived status through its methods.

Given Input: Student s = new Student(new int[]{80, 45, 60, 90, 35});

Average = 62.0
Status = Pass
▼ Hint
  • Loop through the marks array and sum all the values.
  • Divide the sum by marks.length to get the average.
  • Decide on a pass threshold (for example, average of 40 or above) and return “Pass” or “Fail” accordingly.
▼ Solution & Explanation
class Student {
    private int[] marks;

    public Student(int[] marks) {
        this.marks = marks;
    }

    public double getAverage() {
        int total = 0;
        for (int mark : marks) {
            total += mark;
        }
        return (double) total / marks.length;
    }

    public String getStatus() {
        return getAverage() >= 40 ? "Pass" : "Fail";
    }
}

public class Main {
    public static void main(String[] args) {
        Student s = new Student(new int[]{80, 45, 60, 90, 35});
        System.out.println("Average = " + s.getAverage());
        System.out.println("Status = " + s.getStatus());
    }
}Code language: Java (java)

Explanation:

  • private int[] marks: Stores all of the student’s marks as a single array field.
  • for (int mark : marks): Uses an enhanced for loop to add every mark in the array to total.
  • (double) total / marks.length: Casts the sum to double before dividing so the average is not truncated to an integer.
  • getAverage() >= 40 ? "Pass" : "Fail": Uses a ternary operator to return a status string based on the calculated average.

Exercise 6: Car Dashboard

Problem Statement: Design a Car class with attributes make, model, and currentSpeed. Implement accelerate() and brake() methods that change the speed safely.

Purpose: This exercise practices controlling how a field changes over time by keeping the speed within safe bounds, similar to how real dashboard controls prevent invalid states.

Given Input: Car car = new Car("Toyota", "Corolla"); car.accelerate(20); car.brake(30);

Speed increased to 20
Speed cannot go below 0. Speed set to 0
▼ Hint
  • In accelerate(), add the given amount to currentSpeed.
  • In brake(), subtract the given amount, but check if the result would go below zero.
  • If braking would make the speed negative, set currentSpeed to 0 instead.
▼ Solution & Explanation
class Car {
    private String make;
    private String model;
    private int currentSpeed;

    public Car(String make, String model) {
        this.make = make;
        this.model = model;
        this.currentSpeed = 0;
    }

    public void accelerate(int amount) {
        currentSpeed += amount;
        System.out.println("Speed increased to " + currentSpeed);
    }

    public void brake(int amount) {
        if (currentSpeed - amount < 0) {
            currentSpeed = 0;
            System.out.println("Speed cannot go below 0. Speed set to 0");
        } else {
            currentSpeed -= amount;
            System.out.println("Speed decreased to " + currentSpeed);
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Car car = new Car("Toyota", "Corolla");
        car.accelerate(20);
        car.brake(30);
    }
}Code language: Java (java)

Explanation:

  • this.currentSpeed = 0: Initializes the car at a standstill inside the constructor.
  • currentSpeed += amount: Increases the speed field directly when accelerating.
  • if (currentSpeed - amount < 0): Checks whether braking would push the speed below zero before applying the change.
  • currentSpeed = 0: Clamps the speed to zero instead of allowing a negative value when the check fails.

Exercise 7: Inventory Item

Problem Statement: Create a Product class with productID, name, and quantityInStock. Implement methods to addStock(int quantity) and sellProduct(int quantity) while verifying stock availability.

Purpose: This exercise practices guarding a numeric field against invalid operations, a pattern used in inventory and stock management systems to prevent overselling.

Given Input: Product p = new Product(1, "Notebook", 10); p.sellProduct(15);

Expected Output: Not enough stock. Only 10 units available.

▼ Hint
  • In sellProduct(), compare the requested quantity against quantityInStock first.
  • If there is not enough stock, print a message and do not change quantityInStock.
  • In addStock(), simply add the quantity to the existing stock.
▼ Solution & Explanation
class Product {
    private int productID;
    private String name;
    private int quantityInStock;

    public Product(int productID, String name, int quantityInStock) {
        this.productID = productID;
        this.name = name;
        this.quantityInStock = quantityInStock;
    }

    public void addStock(int quantity) {
        quantityInStock += quantity;
        System.out.println("Stock updated. Current stock: " + quantityInStock);
    }

    public void sellProduct(int quantity) {
        if (quantity > quantityInStock) {
            System.out.println("Not enough stock. Only " + quantityInStock + " units available.");
            return;
        }
        quantityInStock -= quantity;
        System.out.println("Sold " + quantity + " units. Remaining stock: " + quantityInStock);
    }
}

public class Main {
    public static void main(String[] args) {
        Product p = new Product(1, "Notebook", 10);
        p.sellProduct(15);
    }
}Code language: Java (java)

Explanation:

  • private int quantityInStock: Tracks how many units of the product are currently available.
  • if (quantity > quantityInStock): Checks whether the requested sale exceeds available stock before making any change.
  • quantityInStock -= quantity: Reduces the stock only after the availability check passes.
  • quantityInStock += quantity: Increases stock directly inside addStock(), since restocking has no upper limit to validate.

Exercise 8: Time Validation

Problem Statement: Create a Time class that stores hours, minutes, and seconds. Use setters to validate that inputs fall within correct time constraints, for example minutes and seconds must be between 0 and 59.

Purpose: This exercise practices validating multiple related fields independently in their own setters, ensuring an object can never hold an invalid combination of values.

Given Input: Time t = new Time(); t.setHours(23); t.setMinutes(75); t.setSeconds(30);

Invalid minutes. Must be between 0 and 59.
Time = 23:0:30
▼ Hint
  • Write a separate setter for each field: setHours(), setMinutes(), and setSeconds().
  • Validate hours to be between 0 and 23.
  • Validate minutes and seconds to be between 0 and 59.
  • Print a message and skip the assignment when a value fails validation.
▼ Solution & Explanation
class Time {
    private int hours;
    private int minutes;
    private int seconds;

    public void setHours(int hours) {
        if (hours < 0 || hours > 23) {
            System.out.println("Invalid hours. Must be between 0 and 23.");
            return;
        }
        this.hours = hours;
    }

    public void setMinutes(int minutes) {
        if (minutes < 0 || minutes > 59) {
            System.out.println("Invalid minutes. Must be between 0 and 59.");
            return;
        }
        this.minutes = minutes;
    }

    public void setSeconds(int seconds) {
        if (seconds < 0 || seconds > 59) {
            System.out.println("Invalid seconds. Must be between 0 and 59.");
            return;
        }
        this.seconds = seconds;
    }

    public void displayTime() {
        System.out.println("Time = " + hours + ":" + minutes + ":" + seconds);
    }
}

public class Main {
    public static void main(String[] args) {
        Time t = new Time();
        t.setHours(23);
        t.setMinutes(75);
        t.setSeconds(30);
        t.displayTime();
    }
}Code language: Java (java)

Explanation:

  • if (hours < 0 || hours > 23): Rejects any hour value outside the valid 24 hour range.
  • if (minutes < 0 || minutes > 59): Rejects an out of range minute value, so minutes keeps its previous default of 0.
  • return;: Exits the setter early when validation fails, leaving the field unchanged.
  • displayTime(): Prints the current values of all three fields together in a readable format.

Exercise 9: Circle Initialization

Problem Statement: Create a Circle class with a radius attribute. Provide a default constructor that sets radius to 1.0, and a parameterized constructor. Use this.radius to resolve naming conflicts.

Purpose: This exercise practices constructor overloading and the use of the this keyword to distinguish between a field and a parameter that share the same name.

Given Input: Circle c1 = new Circle(); Circle c2 = new Circle(5.0);

Radius of c1 = 1.0
Radius of c2 = 5.0
▼ Hint
  • Write a no-argument constructor that assigns 1.0 to radius.
  • Write a second constructor that accepts a radius parameter with the same name as the field.
  • Use this.radius = radius; inside the parameterized constructor so Java knows which one is the field.
▼ Solution & Explanation
class Circle {
    private double radius;

    public Circle() {
        this.radius = 1.0;
    }

    public Circle(double radius) {
        this.radius = radius;
    }

    public double getRadius() {
        return radius;
    }
}

public class Main {
    public static void main(String[] args) {
        Circle c1 = new Circle();
        Circle c2 = new Circle(5.0);
        System.out.println("Radius of c1 = " + c1.getRadius());
        System.out.println("Radius of c2 = " + c2.getRadius());
    }
}Code language: Java (java)

Explanation:

  • public Circle(): The default constructor takes no arguments and sets radius to 1.0.
  • public Circle(double radius): The parameterized constructor has a parameter that shares its name with the field.
  • this.radius = radius: The this keyword refers to the instance field, distinguishing it from the parameter of the same name on the right side.

Exercise 10: Patient Admission (Constructor Chaining)

Problem Statement: Create a Patient class with name, age, and illness. Write three overloaded constructors and use this(...) to chain them so default values are assigned if some data is missing.

Purpose: This exercise practices constructor chaining with this(...), showing how one constructor can call another to avoid duplicating initialization logic while supplying sensible defaults.

Given Input: Patient p1 = new Patient(); Patient p2 = new Patient("Rahul"); Patient p3 = new Patient("Anita", 34, "Fever");

Patient: Unknown, Age: 0, Illness: Not specified
Patient: Rahul, Age: 0, Illness: Not specified
Patient: Anita, Age: 34, Illness: Fever
▼ Hint
  • Write the full constructor first, taking name, age, and illness.
  • Write a constructor that takes only name, and have it call this(name, 0, "Not specified").
  • Write a no-argument constructor that calls this("Unknown") so it chains through the second constructor.
▼ Solution & Explanation
class Patient {
    private String name;
    private int age;
    private String illness;

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

    public Patient(String name) {
        this(name, 0, "Not specified");
    }

    public Patient() {
        this("Unknown");
    }

    public void display() {
        System.out.println("Patient: " + name + ", Age: " + age + ", Illness: " + illness);
    }
}

public class Main {
    public static void main(String[] args) {
        Patient p1 = new Patient();
        Patient p2 = new Patient("Rahul");
        Patient p3 = new Patient("Anita", 34, "Fever");

        p1.display();
        p2.display();
        p3.display();
    }
}Code language: Java (java)

Explanation:

  • public Patient(String name, int age, String illness): The full constructor assigns all three fields directly and is the base that the others chain into.
  • this(name, 0, "Not specified"): The single-argument constructor calls the full constructor, supplying default values for age and illness.
  • this("Unknown"): The no-argument constructor chains into the single-argument constructor, which in turn chains into the full constructor.
  • this(...) must be the first statement: Java requires a constructor call using this(...) to be the very first line inside another constructor.

Exercise 11: Point Duplicator (Copy Constructor)

Problem Statement: Create a Point class representing (x, y) coordinates. Implement a copy constructor that takes another Point object as a parameter and duplicates its coordinates.

Purpose: This exercise introduces the copy constructor pattern, where a new object is built by reading the field values of an existing object of the same class rather than from raw parameters.

Given Input: Point p1 = new Point(3, 4); Point p2 = new Point(p1);

Expected Output: p2 = (3, 4)

▼ Hint
  • Write a regular constructor that accepts x and y values directly.
  • Write a second constructor that accepts a Point object instead of raw values.
  • Inside the copy constructor, read other.x and other.y and assign them to this.x and this.y.
▼ Solution & Explanation
class Point {
    private int x;
    private int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public Point(Point other) {
        this.x = other.x;
        this.y = other.y;
    }

    public void display() {
        System.out.println("(" + x + ", " + y + ")");
    }
}

public class Main {
    public static void main(String[] args) {
        Point p1 = new Point(3, 4);
        Point p2 = new Point(p1);
        System.out.print("p2 = ");
        p2.display();
    }
}Code language: Java (java)

Explanation:

  • public Point(Point other): This is the copy constructor. Its parameter is an existing object of the same class instead of separate primitive values.
  • other.x: Because the code is inside the Point class itself, it can directly read the private fields of another Point object.
  • this.x = other.x: Copies each field from the source object into the new object being constructed.

Exercise 12: Complex Number Addition

Problem Statement: Design a ComplexNumber class with real and imaginary parts. Use a constructor to initialize them, and create a method that accepts another ComplexNumber object to add them together.

Purpose: This exercise practices writing a method that takes an object of its own class as a parameter and returns a new object, a pattern common in mathematical and immutable data classes.

Given Input: ComplexNumber c1 = new ComplexNumber(2, 3); ComplexNumber c2 = new ComplexNumber(4, 5); ComplexNumber sum = c1.add(c2);

Expected Output: Sum = 6 + 8i

▼ Hint
  • Store real and imaginary as fields set in the constructor.
  • Write an add(ComplexNumber other) method that adds the corresponding fields separately.
  • Return a brand new ComplexNumber built from the two sums instead of modifying either original object.
▼ Solution & Explanation
class ComplexNumber {
    private double real;
    private double imaginary;

    public ComplexNumber(double real, double imaginary) {
        this.real = real;
        this.imaginary = imaginary;
    }

    public ComplexNumber add(ComplexNumber other) {
        double newReal = this.real + other.real;
        double newImaginary = this.imaginary + other.imaginary;
        return new ComplexNumber(newReal, newImaginary);
    }

    public void display() {
        System.out.println((int) real + " + " + (int) imaginary + "i");
    }
}

public class Main {
    public static void main(String[] args) {
        ComplexNumber c1 = new ComplexNumber(2, 3);
        ComplexNumber c2 = new ComplexNumber(4, 5);
        ComplexNumber sum = c1.add(c2);
        System.out.print("Sum = ");
        sum.display();
    }
}Code language: Java (java)

Explanation:

  • add(ComplexNumber other): Accepts another ComplexNumber object so its fields can be read and combined with the current object’s fields.
  • this.real + other.real: Adds the real parts of both numbers, keeping the two components separate as complex addition requires.
  • return new ComplexNumber(...): Builds and returns a fresh object holding the result, leaving c1 and c2 unchanged.

Exercise 13: Smartphone Configurator (Method Chaining)

Problem Statement: Create a Smartphone class. Use the this keyword to return the current object instance from your setter methods, allowing you to chain calls like myPhone.setBrand("X").setRAM(8);.

Purpose: This exercise introduces the fluent interface pattern, where setter methods return the object itself so multiple configuration calls can be linked together in a single statement.

Given Input: Smartphone myPhone = new Smartphone(); myPhone.setBrand("Pixel").setRAM(8).setStorage(128);

Expected Output: Brand: Pixel, RAM: 8GB, Storage: 128GB

▼ Hint
  • Give each setter a return type of Smartphone instead of void.
  • At the end of each setter, after assigning the field, add return this;.
  • Because each call returns the same object, the next method in the chain can be called directly on that return value.
▼ Solution & Explanation
class Smartphone {
    private String brand;
    private int ram;
    private int storage;

    public Smartphone setBrand(String brand) {
        this.brand = brand;
        return this;
    }

    public Smartphone setRAM(int ram) {
        this.ram = ram;
        return this;
    }

    public Smartphone setStorage(int storage) {
        this.storage = storage;
        return this;
    }

    public void display() {
        System.out.println("Brand: " + brand + ", RAM: " + ram + "GB, Storage: " + storage + "GB");
    }
}

public class Main {
    public static void main(String[] args) {
        Smartphone myPhone = new Smartphone();
        myPhone.setBrand("Pixel").setRAM(8).setStorage(128);
        myPhone.display();
    }
}Code language: Java (java)

Explanation:

  • public Smartphone setBrand(String brand): The return type is Smartphone instead of void, which is what makes chaining possible.
  • return this;: Returns a reference to the current object, so the result of one setter call can immediately have another setter called on it.
  • setBrand("Pixel").setRAM(8).setStorage(128): Each method call passes the same object reference along the chain, updating one field at a time.

Exercise 14: Flight Tracker

Problem Statement: Create a Flight class where the constructor automatically generates a unique, sequential tracking ID string for every flight instance created.

Purpose: This exercise introduces static fields, showing how a value can be shared and incremented across every instance of a class rather than belonging to just one object.

Given Input: Flight f1 = new Flight(); Flight f2 = new Flight(); Flight f3 = new Flight();

Tracking ID: FL-1
Tracking ID: FL-2
Tracking ID: FL-3
▼ Hint
  • Declare a private static int counter field that is shared by every Flight object.
  • Inside the constructor, increment counter before using it to build the tracking ID.
  • Build the ID string as "FL-" + counter and store it in an instance field.
▼ Solution & Explanation
class Flight {
    private static int counter = 0;
    private String trackingId;

    public Flight() {
        counter++;
        this.trackingId = "FL-" + counter;
    }

    public String getTrackingId() {
        return trackingId;
    }
}

public class Main {
    public static void main(String[] args) {
        Flight f1 = new Flight();
        Flight f2 = new Flight();
        Flight f3 = new Flight();

        System.out.println("Tracking ID: " + f1.getTrackingId());
        System.out.println("Tracking ID: " + f2.getTrackingId());
        System.out.println("Tracking ID: " + f3.getTrackingId());
    }
}Code language: Java (java)

Explanation:

  • private static int counter: A static field belongs to the class itself rather than to any single object, so all Flight instances share and update the same value.
  • counter++: Runs every time a new Flight is constructed, ensuring each instance receives the next number in sequence.
  • this.trackingId = "FL-" + counter: Stores the generated ID as an instance field so it stays fixed for that particular flight after creation.

Exercise 15: Vehicle Customization (Basic Inheritance)

Problem Statement: Create a base class Vehicle with attributes brand and year. Create a subclass Bike that adds a handlebarType attribute. Use super() to initialize the parent attributes.

Purpose: This exercise introduces basic inheritance, showing how a subclass can extend a parent class with its own fields while delegating the initialization of inherited fields to the parent’s constructor.

Given Input: Bike b = new Bike("Yamaha", 2023, "Sport");

Expected Output: Brand: Yamaha, Year: 2023, Handlebar: Sport

▼ Hint
  • Declare Bike using class Bike extends Vehicle.
  • Give Vehicle a constructor that accepts brand and year.
  • In the Bike constructor, call super(brand, year) as the very first line before setting handlebarType.
▼ Solution & Explanation
class Vehicle {
    protected String brand;
    protected int year;

    public Vehicle(String brand, int year) {
        this.brand = brand;
        this.year = year;
    }
}

class Bike extends Vehicle {
    private String handlebarType;

    public Bike(String brand, int year, String handlebarType) {
        super(brand, year);
        this.handlebarType = handlebarType;
    }

    public void display() {
        System.out.println("Brand: " + brand + ", Year: " + year + ", Handlebar: " + handlebarType);
    }
}

public class Main {
    public static void main(String[] args) {
        Bike b = new Bike("Yamaha", 2023, "Sport");
        b.display();
    }
}Code language: Java (java)

Explanation:

  • class Bike extends Vehicle: Makes Bike a subclass of Vehicle, inheriting its brand and year fields.
  • protected String brand; protected int year;: Declared as protected so the subclass can access them directly when needed.
  • super(brand, year): Calls the parent class constructor to initialize the inherited fields before the subclass sets up its own handlebarType field.

Exercise 16: Multilevel Living (Multilevel Inheritance)

Problem Statement: Design an inheritance chain: Animal to Mammal to Dog. Introduce specific behaviors and attributes at each level, showing how properties inherit down the line.

Purpose: This exercise demonstrates multilevel inheritance, where a class inherits from a class that itself inherits from another class, and behavior from every level becomes available at the bottom.

Given Input: Dog d = new Dog(); d.eat(); d.walk(); d.bark();

This animal eats food.
This mammal walks on land.
The dog barks.
▼ Hint
  • Give Animal an eat() method.
  • Make Mammal extends Animal and add a walk() method to it.
  • Make Dog extends Mammal and add a bark() method to it.
  • A Dog object will then have access to all three methods through the inheritance chain.
▼ Solution & Explanation
class Animal {
    public void eat() {
        System.out.println("This animal eats food.");
    }
}

class Mammal extends Animal {
    public void walk() {
        System.out.println("This mammal walks on land.");
    }
}

class Dog extends Mammal {
    public void bark() {
        System.out.println("The dog barks.");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog d = new Dog();
        d.eat();
        d.walk();
        d.bark();
    }
}Code language: Java (java)

Explanation:

  • class Mammal extends Animal: Mammal inherits eat() from Animal while adding its own walk() method.
  • class Dog extends Mammal: Dog inherits both eat() and walk() from the levels above it, then adds bark() of its own.
  • d.eat(); d.walk(); d.bark();: A single Dog object can call methods defined at every level of the chain, since each level builds on the one before it.

Exercise 17: Shape Coloring (Hierarchical Inheritance)

Problem Statement: Create a base class Shape with a color attribute. Create two independent subclasses, Triangle and Square, that inherit the color attribute but define their own distinct geometric dimensions.

Purpose: This exercise demonstrates hierarchical inheritance, where multiple subclasses independently extend the same parent class and each adds its own distinct fields and behavior.

Given Input: Triangle t = new Triangle("Red", 4, 6); Square s = new Square("Blue", 5);

Triangle color: Red, Area: 12.0
Square color: Blue, Area: 25.0
▼ Hint
  • Give Shape a color field and a constructor that sets it.
  • In Triangle, add base and height fields and calculate area as 0.5 * base * height.
  • In Square, add a side field and calculate area as side * side.
  • Both subclasses should call super(color) in their own constructors.
▼ Solution & Explanation
class Shape {
    protected String color;

    public Shape(String color) {
        this.color = color;
    }
}

class Triangle extends Shape {
    private double base;
    private double height;

    public Triangle(String color, double base, double height) {
        super(color);
        this.base = base;
        this.height = height;
    }

    public double getArea() {
        return 0.5 * base * height;
    }
}

class Square extends Shape {
    private double side;

    public Square(String color, double side) {
        super(color);
        this.side = side;
    }

    public double getArea() {
        return side * side;
    }
}

public class Main {
    public static void main(String[] args) {
        Triangle t = new Triangle("Red", 4, 6);
        Square s = new Square("Blue", 5);

        System.out.println("Triangle color: " + t.color + ", Area: " + t.getArea());
        System.out.println("Square color: " + s.color + ", Area: " + s.getArea());
    }
}Code language: Java (java)

Explanation:

  • class Triangle extends Shape and class Square extends Shape: Both subclasses inherit independently from the same parent, each gaining the color field without knowing about the other.
  • super(color): Each subclass constructor passes its color parameter up to the Shape constructor to initialize the inherited field.
  • getArea(): Each subclass defines its own version of this method using the dimensions relevant to its own shape.

Exercise 18: Polite Person (Method Overriding with super)

Problem Statement: Create a parent class Person with a displayDetails() method. Create a subclass Student that overrides this method but calls super.displayDetails() inside it to print the parent data first.

Purpose: This exercise practices method overriding combined with super, showing how a subclass can extend rather than completely replace the behavior of an inherited method.

Given Input: Student s = new Student("Amit", "10th Grade"); s.displayDetails();

Name: Amit
Grade: 10th Grade
▼ Hint
  • Give Person a name field and a displayDetails() method that prints it.
  • In Student, add a grade field and override displayDetails().
  • As the first line of the overridden method, call super.displayDetails() before printing the grade.
▼ Solution & Explanation
class Person {
    protected String name;

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

    public void displayDetails() {
        System.out.println("Name: " + name);
    }
}

class Student extends Person {
    private String grade;

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

    @Override
    public void displayDetails() {
        super.displayDetails();
        System.out.println("Grade: " + grade);
    }
}

public class Main {
    public static void main(String[] args) {
        Student s = new Student("Amit", "10th Grade");
        s.displayDetails();
    }
}Code language: Java (java)

Explanation:

  • @Override: Marks that Student is providing its own version of a method already defined in Person.
  • super.displayDetails(): Explicitly calls the parent class’s version of the method, printing the name before the subclass adds its own output.
  • Combined output: Because the parent method runs first, the final output shows both the inherited name and the subclass grade in one call.

Exercise 19: Variable Shadowing Resolution

Problem Statement: Create a class Parent with an instance variable value. Create a subclass Child that also defines an instance variable named value. Write a method in Child that accesses both variables using super.

Purpose: This exercise demonstrates variable shadowing, where a subclass field with the same name as a parent field hides it, and shows how super can still reach the hidden parent version.

Given Input: Child c = new Child(); c.showValues();

Parent value: 10
Child value: 20
▼ Hint
  • Give both Parent and Child a field named value, set to different numbers.
  • Inside a method in Child, use this.value to refer to the Child field.
  • Use super.value in the same method to reach the hidden Parent field.
▼ Solution & Explanation
class Parent {
    protected int value = 10;
}

class Child extends Parent {
    protected int value = 20;

    public void showValues() {
        System.out.println("Parent value: " + super.value);
        System.out.println("Child value: " + this.value);
    }
}

public class Main {
    public static void main(String[] args) {
        Child c = new Child();
        c.showValues();
    }
}Code language: Java (java)

Explanation:

  • protected int value = 10; in Parent and again in Child: Both classes define a field with the identical name, so the Child version shadows, but does not replace, the Parent version.
  • super.value: Bypasses the shadowing and reaches directly into the Parent class’s copy of value.
  • this.value: Refers to the Child class’s own copy, confirming that both versions of the field exist independently in memory.

Exercise 20: Manager Salary Calculation

Problem Statement: Create an Employee base class and a Manager subclass. The manager’s salary should be calculated as a base salary plus a performance bonus. Pass the base details up via super.

Purpose: This exercise practices combining inheritance with method overriding, where a subclass reuses inherited fields but recalculates a derived value, such as total salary, using its own additional data.

Given Input: Manager m = new Manager("Sunita", 60000, 15000);

Expected Output: Manager: Sunita, Total Salary: 75000.0

▼ Hint
  • Give Employee a constructor accepting name and baseSalary.
  • In Manager, add a bonus field and call super(name, baseSalary) in its constructor.
  • Add a method in Manager that returns baseSalary + bonus as the total salary.
▼ Solution & Explanation
class Employee {
    protected String name;
    protected double baseSalary;

    public Employee(String name, double baseSalary) {
        this.name = name;
        this.baseSalary = baseSalary;
    }
}

class Manager extends Employee {
    private double bonus;

    public Manager(String name, double baseSalary, double bonus) {
        super(name, baseSalary);
        this.bonus = bonus;
    }

    public double getTotalSalary() {
        return baseSalary + bonus;
    }
}

public class Main {
    public static void main(String[] args) {
        Manager m = new Manager("Sunita", 60000, 15000);
        System.out.println("Manager: " + m.name + ", Total Salary: " + m.getTotalSalary());
    }
}Code language: Java (java)

Explanation:

  • super(name, baseSalary): Passes the shared employee details up to the Employee constructor so Manager does not duplicate that assignment logic.
  • private double bonus: Stores the manager-specific value that Employee objects do not have.
  • baseSalary + bonus: Combines the inherited field with the subclass’s own field to compute a value that only makes sense for a Manager.

Exercise 21: Grocery Stock (Perishable Goods)

Problem Statement: Create a base class Item with name and price. Create a subclass PerishableItem that adds an expirationDate attribute and handles specific storage alerts.

Purpose: This exercise practices extending a general class with a more specialized one, adding both a new field and new behavior that only makes sense for that specific subclass.

Given Input: PerishableItem milk = new PerishableItem("Milk", 3.5, "2026-07-05");

Item: Milk, Price: 3.5
Store in refrigerator. Expires on 2026-07-05
▼ Hint
  • Give Item a constructor for name and price, plus a method to display them.
  • In PerishableItem, call super(name, price) and store expirationDate separately.
  • Add a method such as storageAlert() that prints a refrigeration reminder along with the expiration date.
▼ Solution & Explanation
class Item {
    protected String name;
    protected double price;

    public Item(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public void display() {
        System.out.println("Item: " + name + ", Price: " + price);
    }
}

class PerishableItem extends Item {
    private String expirationDate;

    public PerishableItem(String name, double price, String expirationDate) {
        super(name, price);
        this.expirationDate = expirationDate;
    }

    public void storageAlert() {
        System.out.println("Store in refrigerator. Expires on " + expirationDate);
    }
}

public class Main {
    public static void main(String[] args) {
        PerishableItem milk = new PerishableItem("Milk", 3.5, "2026-07-05");
        milk.display();
        milk.storageAlert();
    }
}Code language: Java (java)

Explanation:

  • protected String name; protected double price;: Declared as protected in Item so the subclass can rely on them without needing separate getters.
  • super(name, price): Initializes the inherited fields before PerishableItem sets its own expirationDate.
  • storageAlert(): A method that exists only on PerishableItem, since regular Item objects have no concept of expiration.

Exercise 22: Tiered Banking

Problem Statement: Create a SavingsAccount class that inherits from your original BankAccount class. Add an interestRate attribute and a method applyInterest() that updates the balance using parent-level access.

Purpose: This exercise practices extending a class whose main field is protected rather than public, showing how a subclass can read and modify an inherited field directly while still respecting encapsulation from outside classes.

Given Input: SavingsAccount acc = new SavingsAccount(1000, 5); acc.applyInterest();

Expected Output: New balance after interest: 1050.0

▼ Hint
  • Declare balance as protected in BankAccount so subclasses can access it directly.
  • In SavingsAccount, call super(balance) and store the additional interestRate.
  • In applyInterest(), calculate balance * (interestRate / 100) and add it directly to the inherited balance field.
▼ Solution & Explanation
class BankAccount {
    protected double balance;

    public BankAccount(double balance) {
        this.balance = balance;
    }

    public double getBalance() {
        return balance;
    }
}

class SavingsAccount extends BankAccount {
    private double interestRate;

    public SavingsAccount(double balance, double interestRate) {
        super(balance);
        this.interestRate = interestRate;
    }

    public void applyInterest() {
        balance += balance * (interestRate / 100);
        System.out.println("New balance after interest: " + balance);
    }
}

public class Main {
    public static void main(String[] args) {
        SavingsAccount acc = new SavingsAccount(1000, 5);
        acc.applyInterest();
    }
}Code language: Java (java)

Explanation:

  • protected double balance;: Using protected instead of private allows SavingsAccount to reach the field directly, while classes outside the hierarchy still cannot access it.
  • super(balance): Passes the initial balance up to BankAccount so both classes stay in sync from the moment of construction.
  • balance += balance * (interestRate / 100): Modifies the inherited field directly within the subclass, using data that only SavingsAccount knows about, its interest rate.

Exercise 23: Universal Calculator (Method Overloading)

Problem Statement: Create a MathUtils class featuring overloaded versions of an add() method that can process two integers, three integers, or two double values.

Purpose: This exercise practices method overloading, where multiple methods share the same name but differ in the number or type of their parameters, and the compiler picks the correct one automatically.

Given Input: MathUtils m = new MathUtils(); m.add(2, 3); m.add(2, 3, 4); m.add(2.5, 3.5);

Sum of two ints: 5
Sum of three ints: 9
Sum of two doubles: 6.0
▼ Hint
  • Write three separate add methods, each with a different parameter list.
  • Two methods can share the same number of parameters as long as the parameter types differ, as with add(int, int) versus add(double, double).
  • Java automatically chooses the correct method based on the arguments used at the call site.
▼ Solution & Explanation
class MathUtils {
    public int add(int a, int b) {
        return a + b;
    }

    public int add(int a, int b, int c) {
        return a + b + c;
    }

    public double add(double a, double b) {
        return a + b;
    }
}

public class Main {
    public static void main(String[] args) {
        MathUtils m = new MathUtils();
        System.out.println("Sum of two ints: " + m.add(2, 3));
        System.out.println("Sum of three ints: " + m.add(2, 3, 4));
        System.out.println("Sum of two doubles: " + m.add(2.5, 3.5));
    }
}Code language: Java (java)

Explanation:

  • add(int a, int b) and add(int a, int b, int c): These two methods differ in the number of parameters, which is enough for Java to treat them as separate overloads.
  • add(double a, double b): Has the same parameter count as the first overload but a different parameter type, making it a distinct method.
  • m.add(2, 3) versus m.add(2.5, 3.5): The compiler matches each call to the overload whose parameter types fit the arguments provided.

Exercise 24: Search Directory (Method Overloading)

Problem Statement: Create a UserDirectory class with overloaded findUser() methods: one that searches by an int id, and another that searches by a String username.

Purpose: This exercise practices overloading based on parameter type alone, showing how the same method name can offer two different search strategies depending on what kind of value is passed in.

Given Input: UserDirectory dir = new UserDirectory(); dir.findUser(101); dir.findUser("neha_k");

Searching by ID: 101
Searching by username: neha_k
▼ Hint
  • Write one findUser(int id) method and one findUser(String username) method.
  • Both methods have exactly one parameter, but the parameter types differ, which is enough to overload them.
  • Java decides which method to call based on whether an int or a String is passed as the argument.
▼ Solution & Explanation
class UserDirectory {
    public void findUser(int id) {
        System.out.println("Searching by ID: " + id);
    }

    public void findUser(String username) {
        System.out.println("Searching by username: " + username);
    }
}

public class Main {
    public static void main(String[] args) {
        UserDirectory dir = new UserDirectory();
        dir.findUser(101);
        dir.findUser("neha_k");
    }
}Code language: Java (java)

Explanation:

  • findUser(int id): Handles calls where the argument is a numeric identifier.
  • findUser(String username): Handles calls where the argument is text, even though the method name is identical to the other overload.
  • dir.findUser(101) versus dir.findUser("neha_k"): The compiler resolves which method to run purely by matching the argument’s type against the available overloads.

Exercise 25: Animal Chorus (Runtime Polymorphism)

Problem Statement: Create a base class Animal with a makeSound() method. Override it in Cat (“Meow”) and Dog (“Bark”) subclasses. Create an array of Animal references holding different subclasses and loop through them to trigger their unique sounds.

Purpose: This exercise demonstrates runtime polymorphism, where the specific overridden method that runs is determined by the actual object type, not the reference type used to call it.

Given Input: Animal[] animals = { new Cat(), new Dog() }; for (Animal a : animals) { a.makeSound(); }

Meow
Bark
▼ Hint
  • Give Animal a makeSound() method with generic or empty behavior.
  • Override makeSound() separately in Cat and Dog.
  • Declare the array as Animal[] even though it stores Cat and Dog objects, then call makeSound() on each element inside a loop.
▼ Solution & Explanation
class Animal {
    public void makeSound() {
        System.out.println("Some generic animal sound");
    }
}

class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Meow");
    }
}

class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Bark");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal[] animals = { new Cat(), new Dog() };
        for (Animal a : animals) {
            a.makeSound();
        }
    }
}Code language: Java (java)

Explanation:

  • Animal[] animals = { new Cat(), new Dog() }: The array type is the parent class, but each element is actually a different subclass object underneath.
  • a.makeSound(): Even though a is declared as type Animal, Java calls the overridden version that matches the object’s real class at runtime.
  • Result: The same line of code inside the loop produces different output for each element, which is the essence of runtime polymorphism.

Exercise 26: Dynamic Method Dispatch

Problem Statement: Create a base class Printer with a printDocument() method. Create subclasses LaserPrinter and InkjetPrinter. Demonstrate dynamic method dispatch by assigning subclass objects to a base Printer variable at runtime.

Purpose: This exercise reinforces dynamic method dispatch, showing that the version of an overridden method that gets executed is decided while the program runs, based on the object a reference variable currently points to.

Given Input: Printer p = new LaserPrinter(); p.printDocument(); p = new InkjetPrinter(); p.printDocument();

Printing with laser technology.
Printing with inkjet technology.
▼ Hint
  • Declare a single variable of type Printer.
  • Assign a LaserPrinter object to it first, call printDocument(), then reassign it to a new InkjetPrinter object and call printDocument() again.
  • Each call should run the version defined in whichever subclass the variable currently references.
▼ Solution & Explanation
class Printer {
    public void printDocument() {
        System.out.println("Printing with generic technology.");
    }
}

class LaserPrinter extends Printer {
    @Override
    public void printDocument() {
        System.out.println("Printing with laser technology.");
    }
}

class InkjetPrinter extends Printer {
    @Override
    public void printDocument() {
        System.out.println("Printing with inkjet technology.");
    }
}

public class Main {
    public static void main(String[] args) {
        Printer p = new LaserPrinter();
        p.printDocument();
        p = new InkjetPrinter();
        p.printDocument();
    }
}Code language: Java (java)

Explanation:

  • Printer p = new LaserPrinter();: The reference type is Printer, but the object it points to is a LaserPrinter.
  • p = new InkjetPrinter();: The same variable is reassigned to a different subclass object without changing its declared type.
  • p.printDocument(): Java looks at the actual object p refers to at the moment of the call, not the variable’s declared type, to decide which overridden method runs.

Exercise 27: Payroll Calculation with Overriding

Problem Statement: Create an abstract-like setup where a base class Worker has a calculatePay() method. Subclasses SalariedWorker and HourlyWorker override this method to calculate pay using entirely different formulas.

Purpose: This exercise practices overriding a method where each subclass implements completely different logic, showing that overriding is about replacing behavior, not just extending it.

Given Input: Worker w1 = new SalariedWorker(50000); Worker w2 = new HourlyWorker(25, 160);

Salaried pay: 50000.0
Hourly pay: 4000.0
▼ Hint
  • In SalariedWorker, store a fixed monthlySalary and have calculatePay() simply return it.
  • In HourlyWorker, store hourlyRate and hoursWorked, then have calculatePay() multiply them together.
  • Both classes override the same method name from Worker, but the internal formula is completely unrelated between them.
▼ Solution & Explanation
class Worker {
    public double calculatePay() {
        return 0;
    }
}

class SalariedWorker extends Worker {
    private double monthlySalary;

    public SalariedWorker(double monthlySalary) {
        this.monthlySalary = monthlySalary;
    }

    @Override
    public double calculatePay() {
        return monthlySalary;
    }
}

class HourlyWorker extends Worker {
    private double hourlyRate;
    private double hoursWorked;

    public HourlyWorker(double hourlyRate, double hoursWorked) {
        this.hourlyRate = hourlyRate;
        this.hoursWorked = hoursWorked;
    }

    @Override
    public double calculatePay() {
        return hourlyRate * hoursWorked;
    }
}

public class Main {
    public static void main(String[] args) {
        Worker w1 = new SalariedWorker(50000);
        Worker w2 = new HourlyWorker(25, 160);

        System.out.println("Salaried pay: " + w1.calculatePay());
        System.out.println("Hourly pay: " + w2.calculatePay());
    }
}Code language: Java (java)

Explanation:

  • calculatePay() in Worker: Acts as a placeholder that both subclasses are expected to override with real logic.
  • SalariedWorker.calculatePay(): Simply returns the fixed monthlySalary, ignoring hours entirely.
  • HourlyWorker.calculatePay(): Multiplies hourlyRate by hoursWorked, a formula with no relation to the salaried version.

Exercise 28: String Representation Override

Problem Statement: Create a User class with fields like username and email. Override the built-in Object class toString() method to print a clean, human-readable summary of the user instance instead of its memory address.

Purpose: This exercise introduces overriding a method inherited from Object, the implicit parent of every Java class, and shows how it changes what gets printed when an object is used directly in output.

Given Input: User u = new User("neha_k", "neha@example.com"); System.out.println(u);

Expected Output: User[username=neha_k, email=neha@example.com]

▼ Hint
  • Every Java class implicitly extends Object, which already defines a default toString().
  • Add @Override public String toString() to User and build a formatted string from its fields.
  • When an object is passed to System.out.println(), Java automatically calls its toString() method.
▼ Solution & Explanation
class User {
    private String username;
    private String email;

    public User(String username, String email) {
        this.username = username;
        this.email = email;
    }

    @Override
    public String toString() {
        return "User[username=" + username + ", email=" + email + "]";
    }
}

public class Main {
    public static void main(String[] args) {
        User u = new User("neha_k", "neha@example.com");
        System.out.println(u);
    }
}Code language: Java (java)

Explanation:

  • @Override public String toString(): Replaces the default Object version, which would otherwise print something like a class name followed by a hash code.
  • return "User[username=" + username + ...: Builds a single formatted string that summarizes the object’s key fields.
  • System.out.println(u): Implicitly calls u.toString() behind the scenes, so the overridden version’s output is what actually appears.

Exercise 29: Abstract Classes

Problem Statement: Create an abstract class Shape with an abstract method calculateArea(). Implement concrete subclasses Circle and Rectangle that fill in the specific mathematical formulas.

Purpose: This exercise introduces abstract classes, which define a method signature without any implementation and force every concrete subclass to provide its own version before it can be instantiated.

Given Input: Shape c = new Circle(3); Shape r = new Rectangle(4, 5);

Circle area: 28.26
Rectangle area: 20.0
▼ Hint
  • Mark the class as abstract class Shape and declare public abstract double calculateArea(); with no method body.
  • In Circle, calculate area as Math.PI * radius * radius.
  • In Rectangle, calculate area as length * width. Java will not compile either subclass unless it fully implements calculateArea().
▼ Solution & Explanation
abstract class Shape {
    public abstract double calculateArea();
}

class Circle extends Shape {
    private double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    @Override
    public double calculateArea() {
        return Math.PI * radius * radius;
    }
}

class Rectangle extends Shape {
    private double length;
    private double width;

    public Rectangle(double length, double width) {
        this.length = length;
        this.width = width;
    }

    @Override
    public double calculateArea() {
        return length * width;
    }
}

public class Main {
    public static void main(String[] args) {
        Shape c = new Circle(3);
        Shape r = new Rectangle(4, 5);

        System.out.printf("Circle area: %.2f%n", c.calculateArea());
        System.out.println("Rectangle area: " + r.calculateArea());
    }
}Code language: Java (java)

Explanation:

  • abstract class Shape: An abstract class cannot be instantiated directly with new Shape(), it exists only to be extended.
  • public abstract double calculateArea();: Declares a method signature with no body, meaning every concrete subclass must supply its own implementation.
  • Shape c = new Circle(3);: Even though the reference type is the abstract Shape, the object created is a concrete Circle, which is the only kind of object that can actually exist.

Exercise 30: Appliance Control

Problem Statement: Create an abstract class Appliance with abstract methods turnOn() and turnOff(). Create a concrete subclass AirConditioner that implements these methods and tracks current temperature settings.

Purpose: This exercise extends the abstract class pattern to a case with multiple abstract methods, showing that a concrete subclass must implement every one of them, not just some.

Given Input: Appliance ac = new AirConditioner(22); ac.turnOn(); ac.turnOff();

AC turned on. Temperature set to 22 degrees.
AC turned off.
▼ Hint
  • Declare Appliance as an abstract class with two abstract methods, turnOn() and turnOff(), both without bodies.
  • In AirConditioner, store a temperature field set through the constructor.
  • Implement both abstract methods in AirConditioner, printing a message that references temperature in turnOn().
▼ Solution & Explanation
abstract class Appliance {
    public abstract void turnOn();
    public abstract void turnOff();
}

class AirConditioner extends Appliance {
    private int temperature;

    public AirConditioner(int temperature) {
        this.temperature = temperature;
    }

    @Override
    public void turnOn() {
        System.out.println("AC turned on. Temperature set to " + temperature + " degrees.");
    }

    @Override
    public void turnOff() {
        System.out.println("AC turned off.");
    }
}

public class Main {
    public static void main(String[] args) {
        Appliance ac = new AirConditioner(22);
        ac.turnOn();
        ac.turnOff();
    }
}Code language: Java (java)

Explanation:

  • public abstract void turnOn(); public abstract void turnOff();: Both methods must be implemented by any concrete subclass, since neither has a body in Appliance.
  • private int temperature: A field specific to AirConditioner that has no equivalent in the abstract parent class.
  • turnOn() and turnOff() implementations: Together they satisfy the contract set by Appliance, allowing AirConditioner to be instantiated.

Exercise 31: Flyable Contract

Problem Statement: Create an interface called Flyable with a method fly(). Implement this interface in two completely unrelated classes: Bird and Airplane.

Purpose: This exercise introduces interfaces, showing how two classes with no shared parent class can still guarantee the same behavior by agreeing to a common contract.

Given Input: Flyable b = new Bird(); Flyable a = new Airplane(); b.fly(); a.fly();

The bird flaps its wings to fly.
The airplane uses jet engines to fly.
▼ Hint
  • Declare interface Flyable with a single method signature, void fly();, and no body.
  • Have Bird and Airplane each use implements Flyable instead of extends.
  • Each class must provide its own complete implementation of fly(), since interfaces have no default logic here.
▼ Solution & Explanation
interface Flyable {
    void fly();
}

class Bird implements Flyable {
    @Override
    public void fly() {
        System.out.println("The bird flaps its wings to fly.");
    }
}

class Airplane implements Flyable {
    @Override
    public void fly() {
        System.out.println("The airplane uses jet engines to fly.");
    }
}

public class Main {
    public static void main(String[] args) {
        Flyable b = new Bird();
        Flyable a = new Airplane();
        b.fly();
        a.fly();
    }
}Code language: Java (java)

Explanation:

  • interface Flyable { void fly(); }: Defines a contract that any implementing class must fulfill by providing its own version of fly().
  • class Bird implements Flyable: Bird and Airplane share no class hierarchy at all, yet both satisfy the same interface.
  • Flyable b = new Bird();: A variable of the interface type can reference any object that implements it, regardless of the object’s actual class.

Exercise 32: Hybrid Machines (Multiple Interfaces)

Problem Statement: Create two interfaces: Drivable (startEngine(), stopEngine()) and Watercraft (dock()). Create an AmphibiousVehicle class that implements both interfaces.

Purpose: This exercise demonstrates that a single Java class can implement multiple interfaces at once, something not possible with class inheritance, allowing one class to combine several unrelated behavior contracts.

Given Input: AmphibiousVehicle v = new AmphibiousVehicle(); v.startEngine(); v.dock(); v.stopEngine();

Engine started.
Docking at the harbor.
Engine stopped.
▼ Hint
  • Declare both interfaces separately, each with their own method signatures.
  • In AmphibiousVehicle, use implements Drivable, Watercraft with a comma between the two interface names.
  • Provide implementations for all three methods, startEngine(), stopEngine(), and dock(), inside the single class.
▼ Solution & Explanation
interface Drivable {
    void startEngine();
    void stopEngine();
}

interface Watercraft {
    void dock();
}

class AmphibiousVehicle implements Drivable, Watercraft {
    @Override
    public void startEngine() {
        System.out.println("Engine started.");
    }

    @Override
    public void stopEngine() {
        System.out.println("Engine stopped.");
    }

    @Override
    public void dock() {
        System.out.println("Docking at the harbor.");
    }
}

public class Main {
    public static void main(String[] args) {
        AmphibiousVehicle v = new AmphibiousVehicle();
        v.startEngine();
        v.dock();
        v.stopEngine();
    }
}Code language: Java (java)

Explanation:

  • implements Drivable, Watercraft: A class can implement more than one interface by listing them separated by commas, something Java does not allow with extends for classes.
  • startEngine(), stopEngine(), dock(): All three come from two different interfaces, yet AmphibiousVehicle must implement each one to compile.
  • Combined capability: The single class now satisfies two separate behavior contracts, letting it act as both a drivable vehicle and a watercraft.

Exercise 33: Tax Compliance (Abstract + Interface)

Problem Statement: Create an abstract class Employee and an interface called Taxable. Create a concrete subclass FullTimeEmployee that extends the abstract class and implements the interface.

Purpose: This exercise practices combining extends and implements on the same class, showing how a subclass can inherit shared state from an abstract parent while also fulfilling a separate interface contract.

Given Input: FullTimeEmployee emp = new FullTimeEmployee("Karan", 80000); emp.displayName(); emp.calculateTax();

Employee: Karan
Tax owed: 16000.0
▼ Hint
  • Give the abstract class Employee a name field and a concrete method like displayName().
  • Declare interface Taxable with a method such as calculateTax().
  • Write class FullTimeEmployee extends Employee implements Taxable and implement calculateTax() using a fixed percentage of salary.
▼ Solution & Explanation
abstract class Employee {
    protected String name;

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

    public void displayName() {
        System.out.println("Employee: " + name);
    }
}

interface Taxable {
    void calculateTax();
}

class FullTimeEmployee extends Employee implements Taxable {
    private double salary;

    public FullTimeEmployee(String name, double salary) {
        super(name);
        this.salary = salary;
    }

    @Override
    public void calculateTax() {
        double tax = salary * 0.2;
        System.out.println("Tax owed: " + tax);
    }
}

public class Main {
    public static void main(String[] args) {
        FullTimeEmployee emp = new FullTimeEmployee("Karan", 80000);
        emp.displayName();
        emp.calculateTax();
    }
}Code language: Java (java)

Explanation:

  • class FullTimeEmployee extends Employee implements Taxable: Combines a single class inheritance with an interface contract, both allowed at once in Java.
  • super(name): Initializes the field inherited from the abstract Employee class.
  • calculateTax(): Fulfills the Taxable interface’s contract, using the salary field that belongs only to FullTimeEmployee.

Exercise 34: Default Methods in Interfaces

Problem Statement: Create an interface Vehicle with an abstract method accelerate(). Add a default method inside the interface called soundHorn() so implementing classes automatically inherit a default horn behavior without being forced to write it.

Purpose: This exercise introduces default methods in interfaces, which provide a ready-made implementation that implementing classes can use as is or override if they need different behavior.

Given Input: Vehicle v = new Motorcycle(); v.accelerate(); v.soundHorn();

Motorcycle accelerating.
Beep beep!
▼ Hint
  • Declare accelerate() as a normal abstract method with no body.
  • Declare soundHorn() using the default keyword and give it a complete method body directly inside the interface.
  • A class implementing Vehicle must implement accelerate(), but it can call soundHorn() immediately without writing any code for it.
▼ Solution & Explanation
interface Vehicle {
    void accelerate();

    default void soundHorn() {
        System.out.println("Beep beep!");
    }
}

class Motorcycle implements Vehicle {
    @Override
    public void accelerate() {
        System.out.println("Motorcycle accelerating.");
    }
}

public class Main {
    public static void main(String[] args) {
        Vehicle v = new Motorcycle();
        v.accelerate();
        v.soundHorn();
    }
}Code language: Java (java)

Explanation:

  • void accelerate();: Remains a plain abstract method, so Motorcycle is still required to implement it.
  • default void soundHorn() { ... }: The default keyword allows the interface to supply a working method body, which is unusual for interfaces before this feature existed.
  • v.soundHorn(): Works immediately even though Motorcycle never wrote a soundHorn() method itself, since it inherits the interface’s default implementation.

Exercise 35: E-Commerce Payment Gateway

Problem Statement: Design a PaymentProcessor interface with a processPayment(double amount) method. Implement it across three distinct payment classes: CreditCardProcessor, PayPalProcessor, and CryptoProcessor.

Purpose: This exercise shows a practical use of interfaces for building interchangeable components, where any payment method can be swapped in as long as it follows the same contract.

Given Input: PaymentProcessor[] processors = { new CreditCardProcessor(), new PayPalProcessor(), new CryptoProcessor() }; for (PaymentProcessor p : processors) { p.processPayment(100); }

Processing 100.0 via Credit Card.
Processing 100.0 via PayPal.
Processing 100.0 via Cryptocurrency.
▼ Hint
  • Declare a single method, void processPayment(double amount);, inside PaymentProcessor.
  • Have all three classes implement the interface, each printing a message naming its own payment method.
  • Store all three objects in a single PaymentProcessor[] array so they can be looped through identically despite being different underlying classes.
▼ Solution & Explanation
interface PaymentProcessor {
    void processPayment(double amount);
}

class CreditCardProcessor implements PaymentProcessor {
    @Override
    public void processPayment(double amount) {
        System.out.println("Processing " + amount + " via Credit Card.");
    }
}

class PayPalProcessor implements PaymentProcessor {
    @Override
    public void processPayment(double amount) {
        System.out.println("Processing " + amount + " via PayPal.");
    }
}

class CryptoProcessor implements PaymentProcessor {
    @Override
    public void processPayment(double amount) {
        System.out.println("Processing " + amount + " via Cryptocurrency.");
    }
}

public class Main {
    public static void main(String[] args) {
        PaymentProcessor[] processors = {
            new CreditCardProcessor(),
            new PayPalProcessor(),
            new CryptoProcessor()
        };

        for (PaymentProcessor p : processors) {
            p.processPayment(100);
        }
    }
}Code language: Java (java)

Explanation:

  • PaymentProcessor[] processors: The array type is the interface, so it can hold any object from any class that implements PaymentProcessor.
  • for (PaymentProcessor p : processors): The same loop body works for all three payment types since each guarantees a processPayment() method.
  • Interchangeability: A new payment method could be added later by writing one more class that implements the interface, with no changes needed to the loop itself.

Exercise 36: Instance Counter (Static Keyword)

Problem Statement: Create a Car class that contains a static variable called totalCarsCreated. Increment this counter inside every constructor so you can track how many cars exist globally across your application.

Purpose: This exercise reinforces static fields as class-level state that persists and accumulates across every object created, independent of any single instance.

Given Input: Car c1 = new Car("Honda"); Car c2 = new Car("Ford"); Car c3 = new Car("Kia");

Expected Output: Total cars created: 3

▼ Hint
  • Declare private static int totalCarsCreated = 0; outside of any constructor.
  • Add totalCarsCreated++; as a line inside the constructor.
  • Access the count using a static method or field, since it belongs to the class itself rather than to any one Car object.
▼ Solution & Explanation
class Car {
    private static int totalCarsCreated = 0;
    private String brand;

    public Car(String brand) {
        this.brand = brand;
        totalCarsCreated++;
    }

    public static int getTotalCarsCreated() {
        return totalCarsCreated;
    }
}

public class Main {
    public static void main(String[] args) {
        Car c1 = new Car("Honda");
        Car c2 = new Car("Ford");
        Car c3 = new Car("Kia");

        System.out.println("Total cars created: " + Car.getTotalCarsCreated());
    }
}Code language: Java (java)

Explanation:

  • private static int totalCarsCreated = 0;: A single copy of this variable is shared by the class itself, not duplicated for every object.
  • totalCarsCreated++;: Runs once per constructor call, so the shared counter increases every time a new Car object is created.
  • Car.getTotalCarsCreated(): Called on the class itself rather than on any particular object, which is how static members are typically accessed.

Exercise 37: Immutable Configuration (Final Keyword)

Problem Statement: Create a SystemConfig class with a final variable for DATABASE_URL and a final method showVersion(). Attempt to extend this class or modify these components to observe how Java enforces immutability.

Purpose: This exercise demonstrates the final keyword’s role in preventing change, either by locking a variable’s value after assignment or by blocking a method from being overridden in a subclass.

Given Input: SystemConfig config = new SystemConfig(); config.showVersion();

Expected Output: Version 1.0, DB: jdbc:mysql://localhost:3306/app

▼ Hint
  • Declare public static final String DATABASE_URL = "..."; and assign it once at declaration.
  • Mark showVersion() with the final keyword in its signature.
  • If you try DATABASE_URL = "newValue"; later, or attempt to override showVersion() in a subclass, the code will fail to compile, confirming both are locked.
▼ Solution & Explanation
class SystemConfig {
    public static final String DATABASE_URL = "jdbc:mysql://localhost:3306/app";

    public final void showVersion() {
        System.out.println("Version 1.0, DB: " + DATABASE_URL);
    }
}

// The line below would fail to compile if uncommented, since SystemConfig's
// final method cannot be overridden and its final variable cannot be reassigned.
// class ExtendedConfig extends SystemConfig {
//     public void showVersion() { }
// }

public class Main {
    public static void main(String[] args) {
        SystemConfig config = new SystemConfig();
        config.showVersion();
    }
}Code language: Java (java)

Explanation:

  • public static final String DATABASE_URL = "...";: Once assigned, this value can never be reassigned anywhere else in the program, and any attempt to do so is a compile-time error.
  • public final void showVersion(): The final keyword on a method blocks any subclass from overriding it, keeping its behavior fixed across the entire hierarchy.
  • Immutability guarantee: Both uses of final protect different things, one a value and one a behavior, but both rely on the compiler to enforce the restriction rather than a runtime check.

Exercise 38: The University Setup (Aggregation)

Problem Statement: Create a Professor class. Then, create a Department class that holds a list of Professor objects. Ensure that if the Department is deleted, the Professor objects can still exist independently.

Purpose: This exercise introduces aggregation, a “has-a” relationship where one class holds references to objects that were created outside of it and can outlive it.

Given Input: Professor p1 = new Professor("Dr. Rao"); Professor p2 = new Professor("Dr. Iyer"); Department cs = new Department("Computer Science"); cs.addProfessor(p1); cs.addProfessor(p2); cs.listProfessors();

Computer Science professors:
Dr. Rao
Dr. Iyer
▼ Hint
  • Create Professor objects independently, outside of the Department constructor.
  • Give Department a List<Professor> field and an addProfessor(Professor p) method that simply adds an existing reference to the list.
  • Because the Professor objects are created outside Department and only referenced inside it, they can keep existing even if the Department object is discarded.
▼ Solution & Explanation
import java.util.ArrayList;
import java.util.List;

class Professor {
    private String name;

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

    public String getName() {
        return name;
    }
}

class Department {
    private String deptName;
    private List<Professor> professors;

    public Department(String deptName) {
        this.deptName = deptName;
        this.professors = new ArrayList<>();
    }

    public void addProfessor(Professor p) {
        professors.add(p);
    }

    public void listProfessors() {
        System.out.println(deptName + " professors:");
        for (Professor p : professors) {
            System.out.println(p.getName());
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Professor p1 = new Professor("Dr. Rao");
        Professor p2 = new Professor("Dr. Iyer");

        Department cs = new Department("Computer Science");
        cs.addProfessor(p1);
        cs.addProfessor(p2);
        cs.listProfessors();
    }
}Code language: Java (java)

Explanation:

  • Professor p1 = new Professor("Dr. Rao");: The professor objects are created independently in main(), before any Department exists.
  • addProfessor(Professor p): Department only stores a reference to an already existing Professor object, it does not create the object itself.
  • Independent lifecycle: Because p1 and p2 exist outside cs, they would remain valid objects even if cs were discarded, which is the defining trait of aggregation.

Exercise 39: The Desktop System (Composition)

Problem Statement: Create a Computer class that instantiates its own Processor and GraphicsCard objects inside its constructor. Ensure that if the Computer object is destroyed, its internal component objects are destroyed along with it.

Purpose: This exercise introduces composition, a stricter “has-a” relationship where the contained objects are created and owned entirely by the containing object and cannot exist independently of it.

Given Input: Computer pc = new Computer(); pc.showSpecs();

Processor: Octa-core CPU
Graphics Card: RTX Series
▼ Hint
  • Inside the Computer constructor, directly write this.processor = new Processor(); rather than accepting one as a parameter.
  • Do the same for GraphicsCard.
  • Since both component objects are created entirely inside Computer with no reference kept anywhere else, they only exist as long as their owning Computer object does.
▼ Solution & Explanation
class Processor {
    private String type = "Octa-core CPU";

    public String getType() {
        return type;
    }
}

class GraphicsCard {
    private String model = "RTX Series";

    public String getModel() {
        return model;
    }
}

class Computer {
    private Processor processor;
    private GraphicsCard graphicsCard;

    public Computer() {
        this.processor = new Processor();
        this.graphicsCard = new GraphicsCard();
    }

    public void showSpecs() {
        System.out.println("Processor: " + processor.getType());
        System.out.println("Graphics Card: " + graphicsCard.getModel());
    }
}

public class Main {
    public static void main(String[] args) {
        Computer pc = new Computer();
        pc.showSpecs();
    }
}Code language: Java (java)

Explanation:

  • this.processor = new Processor();: The Computer constructor creates its own Processor object internally, rather than receiving one from outside.
  • this.graphicsCard = new GraphicsCard();: The same pattern applies to GraphicsCard, so both components are fully owned by the Computer instance.
  • Ownership: No other part of the program holds a reference to these Processor or GraphicsCard objects, so they become eligible for garbage collection as soon as the owning Computer object is no longer used.

Exercise 40: State Machine (Enums with OOP)

Problem Statement: Create an enum OrderStatus with states like PENDING, SHIPPED, and DELIVERED. Create an Order class that utilizes this enum, and write a method canCancel() that returns true or false depending on the current enum state.

Purpose: This exercise shows how an enum can represent a fixed, well-defined set of states for an object, and how ordinary logic such as if or switch can branch based on which state is currently active.

Given Input: Order o1 = new Order(OrderStatus.PENDING); Order o2 = new Order(OrderStatus.SHIPPED); System.out.println(o1.canCancel()); System.out.println(o2.canCancel());

true
false
▼ Hint
  • Declare enum OrderStatus { PENDING, SHIPPED, DELIVERED } outside the Order class.
  • Give Order a field of type OrderStatus, set through its constructor.
  • In canCancel(), use a switch or an if comparison to return true only when the status equals OrderStatus.PENDING.
▼ Solution & Explanation
enum OrderStatus {
    PENDING, SHIPPED, DELIVERED
}

class Order {
    private OrderStatus status;

    public Order(OrderStatus status) {
        this.status = status;
    }

    public boolean canCancel() {
        return status == OrderStatus.PENDING;
    }
}

public class Main {
    public static void main(String[] args) {
        Order o1 = new Order(OrderStatus.PENDING);
        Order o2 = new Order(OrderStatus.SHIPPED);

        System.out.println(o1.canCancel());
        System.out.println(o2.canCancel());
    }
}Code language: Java (java)

Explanation:

  • enum OrderStatus { PENDING, SHIPPED, DELIVERED }: Defines a fixed set of named constants that represent every valid state an order can be in.
  • private OrderStatus status;: Stores the order’s current state using the enum type instead of a plain string or number, preventing invalid values.
  • status == OrderStatus.PENDING: Enum constants can be compared directly with ==, returning true only when the order has not yet moved past the pending state.

Filed Under: Java Exercises

Did you find this page helpful? Let others know about it. Sharing helps me continue to create free Python resources.

TweetF  sharein  shareP  Pin

About Vishal

I’m Vishal Hule, the Founder of PYnative.com. As a Python developer, I enjoy assisting students, developers, and learners. Follow me on Twitter.

Related Tutorial Topics:

Java Exercises

All Coding Exercises:

C Exercises
C++ Exercises
Python Exercises
Java Exercises
C# Exercises

Python Exercises and Quizzes

Free coding exercises and quizzes cover Python basics, data structure, data analytics, and more.

  • 15+ Topic-specific Exercises and Quizzes
  • Each Exercise contains 25+ questions
  • Each Quiz contains 25 MCQ
Exercises
Quizzes

Leave a Reply Cancel reply

your email address will NOT be published. all comments are moderated according to our comment policy.

Use <pre> tag for posting code. E.g. <pre> Your entire code </pre>

In: Java Exercises
TweetF  sharein  shareP  Pin

  Java Exercises

  • All Java Exercises
  • Java Exercise for Beginners
  • Java Loops Exercise
  • Java String Exercise
  • Java ArrayList Exercise
  • Java LinkedList Exercise
  • Java HashMap and TreeMap Exercise
  • Java HashSet and TreeSet Exercise
  • Java OOP Exercise
  • Java Methods Exercise
  • Java Enums Exercise
  • Java Exception Handling Exercise
  • Java File Handling Exercise
  • Java Date and Time Exercise
  • Java Data Structures Exercise
  • Java Sorting and Searching Exercise
  • Java Lambda and Functional Interfaces Exercise
  • Java Regex Exercise
  • Java Random Data Generation Exercise
  • Java Generics Exercise
  • Java Reflection Exercise
  • Java JDBC Exercise

All Coding Exercises

Python Exercises C Exercises C++ Exercises Java Exercises C# Exercises

About PYnative

PYnative.com is for Python lovers. Here, You can get Tutorials, Exercises, and Quizzes to practice and improve your Python skills.

Follow Us

To get New Python Tutorials, Exercises, and Quizzes

  • Twitter
  • Facebook
  • Sitemap

Explore Python

  • Learn Python
  • Python Basics
  • Python Databases
  • Python Exercises
  • Python Quizzes
  • Online Python Code Editor
  • Python Tricks

Coding Exercises

  • C Exercises
  • C++ Exercises
  • Python Exercises
  • Java Exercises
  • C# Exercises

Legal Stuff

  • About Us
  • Contact Us

We use cookies to improve your experience. While using PYnative, you agree to have read and accepted our:

  • Terms Of Use
  • Privacy Policy
  • Cookie Policy

Copyright © 2018–2026 pynative.com