Project Based Learning in Java

Classes and Inner Classes

Class members, objects, static utility methods, Math, inner classes, and nested classes.

Lecture 1.2.1 CO2 aligned Unit 1

Learning outcome: Define classes and objects, identify class members, and use member inner and static nested classes correctly.

A class is a blueprint that combines state and behaviour. An object is a runtime instance of that class. Java programs use classes to model entities such as students, accounts, shapes, and devices.

Anatomy of a Class

A class can contain fields, methods, constructors, initialisation blocks, and nested types.

In simple terms: A class is a blueprint, not a building. It lists what every object will have and what it can do, but no memory is set aside until new actually constructs one.

public class Student {
    private String name;                 // field

    public Student(String name) {        // constructor
        this.name = name;
    }

    public void display() {              // method
        System.out.println(name);
    }
}
Member Purpose
Field Stores an object's or class's state.
Constructor Initialises a new object.
Method Defines behaviour.
Initialisation block Runs initialisation code.
Nested class or interface Groups a helper type with its enclosing class.

Creating and Using Objects

The new operator creates an object and invokes its constructor.

This is a two-file example: save the Student class from the preceding section as Student.java, then save the following class as StudentDemo.java in the same folder.

public class StudentDemo {
    public static void main(String[] args) {
        Student first = new Student("Asha");
        Student second = new Student("Ravi");

        first.display();
        second.display();
    }
}

Each object has its own instance fields. A static field belongs to the class and is shared by all objects.

public class Counter {
    private static int objectsCreated;

    public Counter() {
        objectsCreated++;
    }

    public static int getObjectsCreated() {
        return objectsCreated;
    }
}

Static Utility Methods and the Math Class

A static method belongs to the class. It is suitable when an operation depends on its parameters or class-level state and does not require the state of a particular object. Such a method is normally called through the class name.

In simple terms: A static method is a calculator bolted to the wall: it works on whatever numbers you hand it and keeps nothing of its own. Math.sqrt(9) needs no Math object because there is nothing personal to remember.

public class Calculator {
    public static int power(int base, int exponent) {
        if (exponent < 0) {
            throw new IllegalArgumentException(
                    "Integer exponent must not be negative");
        }

        int result = 1;
        for (int count = 0; count < exponent; count++) {
            result = Math.multiplyExact(result, base);
        }
        return result;
    }

    public static double power(double base, int exponent) {
        return Math.pow(base, exponent);
    }

    public static void main(String[] args) {
        System.out.println(Calculator.power(2, 5));
        System.out.println(Calculator.power(2.5, 3));
    }
}

No Calculator object is created. The two methods are overloaded: the compiler selects the int or double version from the argument types. The integer version rejects negative exponents and uses Math.multiplyExact, which throws ArithmeticException instead of silently wrapping if the result exceeds the int range. Math.pow is a static library method and returns a double; casting that result to int would risk truncation, saturation, and floating-point precision loss, so it is not used for the integer version.

Other frequently used methods of Math include abs, max, min, sqrt, round, ceil, and floor.

Use an instance method when Use a static method when
the operation uses an object's fields the result uses parameters or class-level state only
different objects may behave according to their state one class-level utility is sufficient
runtime overriding is required object identity is irrelevant

Member Inner Classes

A non-static class declared inside another class is a member inner class. An inner-class object is associated with an instance of the outer class and can access all members of that instance, including private members.

In simple terms: An inner-class object is a passenger who must be travelling in some particular car. It cannot exist without an outer object, and in exchange it may reach that outer object’s private belongings.

public class Computer {
    private String model = "Lab-PC";

    public class Processor {
        public void showComputer() {
            System.out.println(model);
        }
    }

    public static void main(String[] args) {
        Computer computer = new Computer();
        Computer.Processor cpu = computer.new Processor();
        cpu.showComputer();
    }
}

Static Nested Classes

A static nested class belongs to the outer class rather than to an outer object. It can directly access only the outer class's static members.

In simple terms: A static nested class is a room named after the building rather than owned by any tenant. It is grouped with the outer class for tidiness, but needs no outer object to exist.

public class Converter {
    private static final double RATE = 100.0;

    public static class Centimeter {
        public static double fromMeter(double meter) {
            return meter * RATE;
        }
    }
}

class ConverterDemo {
    public static void main(String[] args) {
        System.out.println(Converter.Centimeter.fromMeter(2.5));
    }
}

No Converter object is required to create or use Converter.Centimeter.

Inner vs Static Nested Class

Question Member inner class Static nested class
Requires an outer object? Yes No
Can directly use outer instance members? Yes No
Can directly use outer static members? Yes Yes
Common purpose Behaviour tied to one outer object Helper type logically grouped with the outer class

Private Inner Classes

An inner class may be private. This hides its implementation while the outer class exposes a simpler public operation.

public class MessageService {
    private class Formatter {
        String format(String text) {
            return "[INFO] " + text;
        }
    }

    public void print(String text) {
        Formatter formatter = new Formatter();
        System.out.println(formatter.format(text));
    }
}

Code outside MessageService cannot name or instantiate Formatter.

Common Mistakes

Mistake Correction
Declaring a top-level class static Only nested classes can be static.
Creating an inner class without an outer object Use outer.new Inner().
Accessing an outer instance field from a static nested class Supply an outer object or make the required member static.
Making every class member public Use the most restrictive access that supports the design.

Practice

  1. Create a Book class with title, price, a constructor, and a display() method.
  2. Add a static field that counts how many Book objects are created.
  3. Create overloaded static power methods for integer and double bases; avoid converting the double result of Math.pow back to int.
  4. Create an Engine inner class inside Car and let it print the car's private model.
  5. Create a static nested Validator class inside User.

Quick Check

1. What is the difference between a class and an object?

A class is a blueprint that declares state and behaviour. An object is a runtime instance created from that blueprint.

2. Can a static nested class directly access an outer object's fields?

No. It can directly access only static members of the outer class. It needs an outer object to access instance members.

3. Why use a private inner class?

It keeps a helper implementation hidden and closely grouped with the outer class that uses it.

4. Must an object be created before calling a static method?

No. A static method belongs to the class and is normally called through the class name.

Summary

Classes define fields, constructors, and methods; objects carry the resulting runtime state. Static utility methods support operations that do not require object state. A member inner class belongs to an outer object, while a static nested class belongs to the outer class. Nested types are valuable when a helper concept is meaningful only inside one enclosing class.