Skip to main content

Object oriented programming

Understanding types of classes in java

Types of classes in java

Concrete Class:

A fundamental class type that serves as a blueprint for creating objects. Defines both properties (variables) and behavior (methods) of the objects. Can be directly instantiated to create objects. Example:

public class Car {
	String color;
	int speed;

	public void accelerate() {
		speed++;
	}

	public void brake() {
		speed--;
	}

	public static void main(String[] args) {
		Car myCar = new Car(); // Create an object of Car
		myCar.color = "Red";
		myCar.accelerate();
		System.out.println("Car color: " + myCar.color + ", Speed: " + myCar.speed);
	}
}

Abstract Class:

Acts as a template for subclasses and cannot be directly instantiated. Defines a common structure and behavior for related classes. Can have abstract methods (without a body) that subclasses must implement. Enforces consistency and ensures subclasses provide required functionality. Example:

public abstract class Animal {
    public abstract void makeSound(); // Abstract method

    public void sleep() {
        System.out.println("Animal is sleeping...");
    }
}

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

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

Interface:

Similar to an abstract class, but defines only abstract methods (no implementation). Acts as a contract that specifies what functionality a class must provide. A class can implement multiple interfaces. Example:

public interface Shape {
    double calculateArea();
}

public class Circle implements Shape {
    double radius;

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

public class Square implements Shape {
    double side;

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

Final Class:

Cannot be subclassed. Prevents further inheritance from that class. Useful for representing fixed concepts or preventing unintended modifications. Methods within a final class can also be declared as final to prevent overriding in subclasses. Example:

public final class MathUtil {
    public static final double PI = 3.14159; // Final static variable

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

Inner Class:

A class defined within another class. Provides access to the enclosing class's members.

There are four types of inner classes:

Static Nested Class: Defined with static keyword. Can access only static members of the enclosing class.

public class OuterClass {
    public static class StaticNestedClass {
        public void printMessage() {
            System.out.println("Message from Static Nested Class");
        }
    }
}

Member Inner Class: Defined without static keyword. Can access both static and non-static members of the enclosing class. Needs an object reference of the outer class to be accessed.

public class OuterClass {
    private int data = 10;

    public class MemberInnerClass {
        public void printData() {
            System.out.println("Data from Outer Class: " + data);
        }
    }
}

Local Inner Class: Defined within a method. Short-lived and can access local variables of the enclosing method.

public class OuterClass {
    public void someMethod() {
        int value = 5;

        class LocalInnerClass {
            public void printValue() {
                System.out.println("Local variable from enclosing method: " + value);
            }
        }

        LocalInnerClass inner = new LocalInnerClass();
        inner.printValue();

    }
}

Anonymous Inner Class: Defined and instantiated at the same time, without a separate class name. Often used for implementing interfaces or simple functionality on the fly.

Syntax
new InterfaceName() {
// Implement interface methods here
}

Button myButton = new Button("Click Me");

// Anonymous inner class implementing ActionListener
myButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Button clicked!");
// You can add more logic here, like opening a new window, etc.
}
});

Sealed Class (Java 15):

Restricts inheritance hierarchy by specifying allowed subclasses. Enhances control over class relationships and prevents unintended extensions.


public sealed class Shape permits Circle, Square {
    public abstract double calculateArea();
}

public final class Circle extends Shape {
    double radius;

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

// Square can inherit from Shape because it's listed in the `permits` clause
public class Square extends Shape {
    double side;

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

// This would cause a compile-time error because Triangle is not permitted
// public class Triangle extends Shape { ... }

POJO (Plain Old Java Object):

This is not a technical class type but rather a design pattern. A POJO class is a simple class that focuses on data storage and retrieval. It typically has private member variables and public getter and setter methods to access and modify the data.

POJOs are often used for data transfer between applications or persistence with databases.

Here's a POJO example of a Person class with name and age in Java:

Java
public class Person {

    private String name;
    private int age;

    // Default constructor (optional, but good practice)
    public Person() {}

    // Constructor with arguments (allows initializing name and age during object creation)
    public Person(String name, int age) {
		            this.name = name;
                this.age = age;
            }

            // Getter for name
            public String getName() {
                return name;
            }

            // Setter for name
            public void setName(String name) {
                this.name = name;
                }

                // Getter for age
                public int getAge() {
                    return age;
                }

                // Setter for age (can add validation here to ensure positive age)
                public void setAge(int age) {
                    if (age < 0) {
                        throw new IllegalArgumentException("Age cannot be negative");
                    }
                    this.age = age;
                }

                // You can add other methods specific to Person objects here (e.g., introduce themselves)

                @Override
                public String toString() {
                    return "Person [name=" + name + ", age=" + age + "]";
                }
            }

Record Class (Java 14):

Concise way to define immutable data holder classes. Reduces boilerplate code for getters, equals(), hashCode(), and toString().


public record Person(String name, int age) {
// Implicit constructor, getters (name(), age()), equals(), hashCode(), toString()
}