Object-oriented programming rests on four foundational concepts that together shape how we model and organize software. Encapsulation is the practice of bundling data and the methods that operate on that data into a single unit, typically a class, while restricting direct access to some of the object's components. By hiding internal state and implementation details behind a controlled public interface, encapsulation protects object integrity and prevents unintended modification from outside code.
Inheritance allows a child class, or subclass, to acquire the properties and behaviors of a parent class, or superclass. In Java, declaring a Dog class with the extends keyword so that it inherits from Animal establishes a clear is-a relationship in which Dog is a specific kind of Animal. This mechanism promotes code reuse by allowing common behavior to live in a parent class, while also enabling polymorphic behavior when subclasses provide their own specialized implementations.
Polymorphism, literally meaning "many forms," is the ability of an object to take on different behaviors depending on its actual type. It comes in two main forms: compile-time polymorphism achieved through method overloading, where the compiler picks the right method based on argument types, and run-time polymorphism achieved through method overriding, where the call is resolved at runtime based on the object's actual class. A draw method on a Shape, for instance, will render a Circle differently from a Rectangle even when invoked through a common Shape reference.
Abstraction focuses on hiding complex implementation details and exposing only the essential features of an object. In practice, this is achieved through abstract classes that provide partial implementations, and through interfaces that define a pure contract with no implementation at all. A Vehicle interface, for example, might expose only start and stop methods, deliberately concealing the intricacies of how engines actually work.