๐Ÿ“š Java OOP Fundamentals: Classes, Objects, Inheritance, and More

Understanding Java's object-oriented programming (OOP) concepts is essential for writing clean, reusable, and maintainable code. This post explores classes, objects, OOP principles, functional programming concepts, and key Java features.

1. ๐Ÿงฉ OOP vs Functional Programming

  • OOP: mutable objects, classes, state stored in objects.
  • Functional: immutable, functions as first-class citizens, easy parallelization, fewer bugs.

2. ๐Ÿ“ฆ Classes & Objects

Classes are templates for creating objects with fields, methods, and constructors. Objects are instances of classes.

2.1 ๐Ÿ’ก Java: Pass by Value

Java is always pass-by-value. This means:

  • Primitive types: The actual value is copied and stored on the stack. Changes inside a method do not affect the original variable.
  • Non-primitive types (Objects): The reference to the object is copied (stored on the stack), pointing to the object in the heap. Changes to the object's state affect the original object, but reassigning the reference does not.

Example:


// Primitive example
int x = 10;
void modify(int a) { a = 20; }
modify(x);
System.out.println(x); // prints 10

// Object example
class Person { String name; }
Person p = new Person();
p.name = "Alice";
void change(Person obj) { obj.name = "Bob"; }
change(p);
System.out.println(p.name); // prints "Bob"

Understanding this concept is key for avoiding unexpected side effects and writing safer, predictable Java code.

3. ๐Ÿ”‘ OOP Principles

  • Abstraction: Hide complex implementation, expose only API.
  • Encapsulation: Hide internal state, control access via private, protected, public.
  • Inheritance: "Is-A" relationship, allows code reuse (extends), single inheritance in Java.
  • Polymorphism: Same interface, different implementations. Includes overloading (compile-time) and overriding (runtime).

4. ๐Ÿงฑ Relationships

  • Association: Relation between classes (1:1, 1:many).
  • Composition: "Has-a" with ownership (parts destroyed with owner).
  • Aggregation: "Has-a" without ownership (parts can exist independently).

5. ⚙️ Generics

Generics allow reusable code with type safety. Compile-time checking avoids runtime ClassCastException.

6. ๐Ÿงพ equals() & hashCode()

Objects equal by equals() must have the same hashCode(). Same hashCode doesn’t guarantee equals.

7. ๐Ÿ“ Interfaces & Abstract Classes

Interfaces define behaviors; abstract classes provide shared default behavior while allowing variations in subclasses.

Feature Interface Abstract Class
Methods Can only declare abstract methods (Java 8 onwards allows default and static methods). Can declare both abstract and concrete (implemented) methods.
Method Implementation All methods are by default abstract unless declared as default (Java 8+) or static. Can provide complete, partial, or no implementation.
Variables All variables are implicitly public, static, and final. Can have any type of variable (public, protected, private, static, non-static, final, non-final).
Inheritance Allows multiple inheritance, as a class can implement multiple interfaces. Allows single inheritance only. A class can extend only one abstract class.
Usage Used to define a contract for what a class should do, not how it does it. Used when classes share some behavior (implementation) but differ in specifics.
Access Modifiers Methods and variables are implicitly public. Can have public, protected, and private methods and fields.
Object Creation Cannot be instantiated directly. Cannot be instantiated directly, but can include constructors to initialize fields in subclasses.
When to Use Use when you want to specify that a class must adhere to a specific behavior without sharing implementation. Use when classes should share some implementation details or common structure, with some flexibility for subclass.

8. ๐Ÿ”ค Strings & Mutable Objects

  • String: Immutable
  • StringBuilder: Mutable, non-synchronized
  • StringBuffer: Mutable, synchronized
  • String Pool: storage for string literals in heap

9. ๐Ÿ’พ Serialization & Concurrency

  • Serialization: convert object state to byte stream (used in JPA, JMS, Hibernate)
  • transient: field not serialized
  • volatile: read directly from memory, useful in concurrency

10. ⚠️ Exceptions

  • Error: unchecked
  • Exception: checked & runtime
  • Runtime Exceptions: e.g., IndexOutOfBoundsException
  • Checked Exceptions: e.g., IOException

11. ๐Ÿ“Š Comparable & Comparator

In Java, Comparable and Comparator are used to define how objects are ordered. They are commonly used with collections such as List, Set, and sorting utilities.

Comparable — Natural Ordering

Comparable defines a single, natural ordering for a class by implementing the compareTo method.

  • Implemented inside the class
  • Defines the default sort order
  • Used automatically by Collections.sort()

public class User implements Comparable<User> {
    private String name;
    private int age;

    @Override
    public int compareTo(User other) {
        return Integer.compare(this.age, other.age); // sort by age
    }
}

Usage:


List<User> users = List.of(
    new User("Alice", 30),
    new User("Bob", 25)
);

Collections.sort(users); // uses compareTo()

Limitation: only one sorting strategy can be defined.


Comparator — Multiple Sorting Strategies

Comparator defines ordering outside the class and allows multiple sorting strategies.

  • External to the class
  • Multiple comparators possible
  • Ideal when you cannot modify the class

// Sort by name
Comparator<User> byName =
    (u1, u2) -> u1.getName().compareTo(u2.getName());

// Sort by age descending
Comparator<User> byAgeDesc =
    (u1, u2) -> Integer.compare(u2.getAge(), u1.getAge());

Usage:


users.sort(byName);
users.sort(byAgeDesc);

Comparator Utilities (Java 8+)

Java 8 introduced fluent, readable comparator helpers:


users.sort(
    Comparator.comparing(User::getAge)
              .thenComparing(User::getName)
);

Reverse order:


users.sort(Comparator.comparing(User::getAge).reversed());

Comparable vs Comparator — Summary

Aspect Comparable Comparator
Location Inside the class Outside the class
Method compareTo() compare()
Sort Order Single (natural order) Multiple strategies
Flexibility Low High
When to Use Class has an obvious natural order Different sorting needs or external classes

Rule of thumb: use Comparable for a class’s natural identity order, and Comparator for business-specific or dynamic sorting logic.

Labels: Java, OOP, Functional Programming, Classes, Objects, Inheritance, Polymorphism, Generics, Exceptions

Comments

Popular posts from this blog

๐Ÿ› ️ The Code Hut - Index

๐Ÿ›ก️ Resilience Patterns in Distributed Systems

๐Ÿ›ก️ Thread-Safe Programming in Java: Locks, Atomic Variables & LongAdder