Fundamentals of Programming Paradigms
Java supports two distinct development approaches: Procedure Oriented Programming (POP) and Object Oriented Programming (OOP). POP focuses on the sequence of operations required to solve a problem, decomposing logic into functions. Conversely, OOP centers on objects that encapsulate both state and behavior. While POP suits simple scripts or embedded systems where performance is critical and abstraction overhead must be minimized, OOP excels in complex applications by promoting modularity through encapsulation, inheritance, and polymorphism.
Class Definition and Instantiation
A class serves as the blueprint defining the structure of a object, while the object represents a concrete instance of that blueprint. To define a class, developers use the class keyword followed by a name adhering to CamelCase conventions. Fields (properties) determine the state, and methods define behavior.
public class Book {
private String title;
private int publicationYear;
public void displayInfo() {
System.out.println("Title: " + title + ", Year: " + publicationYear);
}
}
Creating an object requires the new operator and typically invokes a constructor. This process allocates memory on the heap and returns a reference stored in a stack variable.
Book myBook = new Book();
myBook.title = "Java Basics";
myBook.displayInfo();
Instance versus Static Members
Class members exist either per-instance or at the class level. Instance members belong to specific object instances, meaning each object maintains its own copy of these variables. Static members are associated with the class itself and are shared across all instances.
Field Differences
- Static Fields: Defined using the
statickeyword. They load when the class loads into the JVM. All objects access the same memory location. - Instance Fields: Exist within each object's memory space. Initialized upon object creation unless default values are assigned.
Method Differences
- Static Methods: Accessible via the class name without instantiation. They can only interact with static data directly.
- Instance Methods: Require a object reference to execute. They possess full access to both static and non-static members via the
thispointer.
Initialization via Constructors
Constructors initialize new objects. They share the class name but lack return types. Overloading allows multiple constructors to handle different initialization scenarios.
public class Product {
private String sku;
private double price;
// Default constructor initializes empty state
public Product() {
this.sku = "0000";
this.price = 0.0;
}
// Parameterized constructor
public Product(String sku, double price) {
this.sku = sku;
this.price = price;
}
public String getSku() { return sku; }
public double getPrice() { return price; }
}
When invoking new Product(id, cost), the parameterized block runs. If no explicit constructor is provided, the compiler injects a default no-argument constructor.
Memory Management and Lifecycle
Objects reside in heap memory. Their lifespan depends on reachability from root references. The Garbage Collector (GC) automatically reclaims memory for unreachable objects. Developers do not manually delete objects using delete like in C++, but they should close external resources (files, sockets) explicitly using try-with-resources or close() methods.
Object comparison logic relies on equals() for content equality, whereas == checks reference identity. To override default equality checks:
@Override
public boolean equals(Object other) {
if (this == other) return true;
if (!(other instanceof Product)) return false;
return Double.compare(price, ((Product) other).price) == 0;
}
Anonymous Objects
An anonymous object is instantiated without assigning it to a named varible. This pattern is useful for one-off method invocations where intermediate storage is unnecessary.
new Product("ITEM-1", 99.99).getPrice();
// Output happens immediately; the object becomes eligible for GC shortly after
While concise, overusing anonymous objects can obscure logic, particularly when complex initialization or state tracking is needed later.
Advanced Creation Strategies
Besides standard instantiation with new, other mechanisms include:
- Factory Methods: Encapsulate creation logic within static methods returning an interface type.
- Reflection: Dynamically instantiate classes based on string names known only at runtime (
Class.forName().newInstance()). - Cloning: Create copies using the
Cloneableinterface.
These techniques support design patterns like Singleton or Factory but introduce complexity and potential security risks compared to direct construction.