๐ 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
Post a Comment