Object-Oriented Programming with Java


Target Audience
This blog post is designed to cater to two primary groups of individuals:
1. Intermediate Developers in Java
If you are already familiar with Object-Oriented Programming (OOP) principles in Java but encounter uncertainties or complexities in their implementation, this content is tailored to address your concerns. You might be seeking clarification on advanced OOP concepts like inheritance, and polymorphism, or facing challenges when applying OOP principles to real-world Java projects. This guide aims to help refine your understanding, resolve doubts, and enhance your proficiency in utilizing OOP effectively within Java.
2. Beginners Exploring OOP in Java
If you're new to programming or transitioning to Java from another language, this blog post provides an ideal starting point to grasp the fundamental concepts of Object-Oriented Programming. Whether you're aiming to comprehend classes, objects, encapsulation, or inheritance, this guide breaks down these concepts in a straightforward manner within the context of Java. It is tailored to empower beginners, offering a solid foundation to embark on your programming journey confidently.
No matter your level of expertise, whether you're seeking clarification on intricate OOP concepts or just starting your Java programming journey, this post aims to provide comprehensive insights and practical examples to support your learning.
Introduction
Object-oriented programming (OOP) is a programming paradigm that organizes software design around data, or objects, rather than functions and logic. It's a way of thinking and structuring code that promotes modularity, maintainability, and reusability.
Now you thinking about what is a programming paradigm. you can check this article Basics of Programming Paradigms
OOPs Concepts
Objects: Real-world objects share two characteristics: They all have state and behavior. Dogs have state (name, color) and behavior (barking, wagging tail). Software objects are conceptually similar to real-world objects: they too consist of state and related behavior. An object stores its state in fields (variables in some programming languages) and exposes its behavior through methods (functions in some programming languages). We can simply say that any entity that has state and behavior is known as an object.
Class: A class is the blueprint from which individual objects are created. In the real world, you'll often find many individual objects all of the same kind. There may be thousands of other bicycles in existence, all of the same make and model. Each bicycle was built from the same set of blueprints and therefore contains the same components.
public class Dog { // State private String name; private String color; private boolean isHungry; // Blueprint - Constructor initializes the state public Dog(String name, String color) { this.name = name; this.color = color; this.isHungry = true; // Dogs start as hungry } // Behavior - Method to make the dog bark public void bark() { System.out.println(name + " says Woof!"); } // Behavior - Method to make the dog wag its tail public void wagTail() { System.out.println(name + " wags its tail happily."); } // Displaying the state of the dog public void displayState() { System.out.println(name + " is a " + color + " dog."); System.out.println(name + " is " + (isHungry ? "hungry." : "not hungry.")); } public static void main(String[] args) { // Creating an individual dog object based on the blueprint Dog myDog = new Dog("Buddy", "Brown"); // Accessing behavior and state of the dog object myDog.displayState(); myDog.bark(); myDog.wagTail(); myDog.displayState(); } }
This code defines a
Dog
class that encapsulates the state (name, color, isHungry) and behavior (bark, wagTail, displayState) of a dog. Themain
method creates an instance of theDog
class and demonstrates its behavior and state.Inheritance: Inheritance is a powerful mechanism that allows you to create new classes based on existing classes. This new class inherits all the attributes and methods of the parent class, and can also add its own unique attributes and methods.
Inheritance represents the IS-A relationship which is also known as a parent-child relationship.
Based on class, there can be three types of inheritance in Java:
single, multilevel and hierarchical.
In Java programming, multiple and hybrid inheritance is supported through the interface only.
// Superclass - Vehicle class Vehicle { private String brand; private String model; public Vehicle(String brand, String model) { this.brand = brand; this.model = model; } public void displayInfo() { System.out.println("Brand: " + brand); System.out.println("Model: " + model); } } // Subclass - Car (inherits from Vehicle) class Car extends Vehicle { private int numberOfDoors; public Car(String brand, String model, int doors) { super(brand, model); // Call to superclass constructor this.numberOfDoors = doors; } public void displayCarInfo() { super.displayInfo(); // Calling superclass method System.out.println("Number of Doors: " + numberOfDoors); } } // Usage public class VehicleDemo { public static void main(String[] args) { // Creating an instance of Car (subclass) Car myCar = new Car("Toyota", "Corolla", 4); // Accessing and displaying information using subclass method myCar.displayCarInfo(); } }
Bicycle
serves as the superclass with common attributes and methods likecurrentSpeed
,currentGear
,speedUp
,applyBrakes
,changeGear
, andprintStatus
. Each subclass (MountainBike
,RoadBike
,TandemBike
) extendsBicycle
to inherit these functionalities and can also include their specific attributes and methods, such asshockLevel
,tireWidth
, andnumberOfSeats
. Themain
method inBikeDemo
creates instances of each bike type and demonstrates their unique behaviors.Aggregation: Aggregation is a special type of association between objects. It describes a scenario where one object (the whole) contains or owns another object (the part). Unlike inheritance, there is no parent-child relationship, and the objects coexist independently.
Aggregation represents HAS-A relationship.
// Engine class class Engine { private String type; public Engine(String type) { this.type = type; } public void start() { System.out.println("Engine started."); } public void stop() { System.out.println("Engine stopped."); } } // Car class using aggregation class Car { private String brand; private String model; private Engine carEngine; // Aggregation - Car has an Engine public Car(String brand, String model, Engine engine) { this.brand = brand; this.model = model; this.carEngine = engine; } public void startCar() { System.out.println("Starting the car's engine."); carEngine.start(); // Using Engine functionality through aggregation } public void stopCar() { System.out.println("Stopping the car's engine."); carEngine.stop(); // Using Engine functionality through aggregation } } // Usage public class CarDemo { public static void main(String[] args) { // Creating an Engine object Engine v8Engine = new Engine("V8"); // Creating a Car object using the Engine object through aggregation Car myCar = new Car("Toyota", "Corolla", v8Engine); // Starting and stopping the car's engine myCar.startCar(); myCar.stopCar(); } }
Vehicle
is a superclass withbrand
andmodel
attributes and a methoddisplayInfo
to show the vehicle's information.Car
is a subclass ofVehicle
that inherits the attributes and methods fromVehicle
and adds its own attributenumberOfDoors
. It also includes a methoddisplayCarInfo
to display car-specific information along with the inherited vehicle information. Themain
method inVehicleDemo
creates an instance ofCar
and demonstrates using thedisplayCarInfo
method to showcase the information of both theVehicle
andCar
objects, emphasizing inheritance whereCar
gains access to the attributes and methods of its superclassVehicle
.
Polymorphism: Polymorphism, a key concept in object-oriented programming, refers to the ability of a single interface (such as a method or function) to be used for different types or instances, allowing for flexibility and extensibility in code.
There are two types of polymorphism: compile-time (or static) polymorphism and runtime (or dynamic) polymorphism.
Compile-time Polymorphism (Method Overloading): This occurs when there are multiple methods in the same class with the same name but different parameters. The decision about which method to call is made by the compiler based on the method signature during compile-time.
class Calculation { public int add(int a, int b) { return a + b; } public double add(double a, double b) { return a + b; } }
Here, the
add
method is overloaded with different parameter types (integers and doubles), allowing different behaviors depending on the arguments passed.Runtime Polymorphism (Method Overriding): This occurs when a subclass provides a specific implementation of a method that is already defined in its superclass. The decision about which method to call is made at runtime based on the actual object being referred to.
class Animal { public void makeSound() { System.out.println("Some sound"); } } class Dog extends Animal { @Override public void makeSound() { System.out.println("Bark"); } } class Cat extends Animal { @Override public void makeSound() { System.out.println("Meow"); } }
Here, both
Dog
andCat
classes override themakeSound
method inherited from theAnimal
superclass, providing specific sound implementations. The actual behavior ofmakeSound
is determined by the type of object at runtime.
Abstraction: Abstraction is a fundamental principle in object-oriented programming that focuses on hiding complex implementation details while showing only the essential features of an object.
An interface is a group of related methods with empty bodies.
There are two primary aspects to abstraction:
Hiding Complexity: Abstraction allows us to focus on the necessary aspects of an object while hiding the unnecessary details. It simplifies the interaction with objects by exposing only the essential methods and properties.
Creating Interfaces: Abstraction involves creating interfaces or abstract classes that define a set of methods or properties without providing the implementation details. These methods serve as a contract for the behavior expected from the implementing classes.
// Abstract class defining an interface abstract class Shape { // Abstract method - no implementation details provided public abstract double area(); } // Concrete classes implementing Shape class Circle extends Shape { private double radius; public Circle(double radius) { this.radius = radius; } @Override public double area() { return Math.PI * radius * radius; } } class Rectangle extends Shape { private double length; private double width; public Rectangle(double length, double width) { this.length = length; this.width = width; } @Override public double area() { return length * width; } }
In this example,
Shape
is an abstract class defining an abstract methodarea()
without providing an implementation. TheCircle
andRectangle
classes extendShape
and provide their own implementations of thearea()
method specific to their shapes. This abstraction allows users to work with shapes without worrying about the specific details of how the area is calculated for each shape.
Encapsulation: Encapsulation in Java is a process of wrapping code and data together into a single unit, for example, a capsule that is mixed with several medicines.bject-oriented-programming-with
// Class demonstrating encapsulation class Car { // Private attributes private String model; private int year; // Public methods to access and modify private attributes (getters and setters) public String getModel() { return model; } public void setModel(String model) { this.model = model; } public int getYear() { return year; } public void setYear(int year) { if (year > 0) { this.year = year; } else { System.out.println("Invalid year!"); } } } // Usage public class EncapsulationExample { public static void main(String[] args) { // Creating an instance of Car Car myCar = new Car(); // Accessing and modifying the attributes through methods (encapsulated) myCar.setModel("Toyota"); myCar.setYear(2022); // Retrieving attribute values through methods System.out.println("Car Model: " + myCar.getModel()); System.out.println("Car Year: " + myCar.getYear()); } }
Car
class encapsulatesmodel
andyear
attributes, making them private.Public methods (
getters
andsetters
) provide controlled access to these attributes, allowing users to get and set their values while enforcing validation rules (e.g., ensuring a positive year value).The
main
method demonstrates how external code interacts with theCar
object through its public methods without directly accessing its private attributes. This maintains encapsulation by hiding the internal state of theCar
object.
Benefits of Object-Oriented Programming with Java
Modularity and Reusability: OOP encourages breaking down code into smaller, manageable modules (classes and objects) that can be reused across different parts of an application or in other projects. This reusability saves time and effort in development.
Maintainability and Scalability: By organizing code around objects and their interactions, OOP promotes code that is easier to maintain and extend. Changes to one part of the codebase are less likely to affect other parts, making maintenance and updates more straightforward.
Abstraction for Conceptual Clarity: Abstraction allows developers to focus on essential details while hiding unnecessary complexities. This clarity in design and implementation aids in better understanding and collaboration among developers.
Encapsulation for Security and Control: Encapsulation helps in controlling access to certain parts of code and data, providing security by preventing unauthorized access or modifications. This control ensures data integrity and reduces the chances of errors.
Facilitates Problem-Solving: OOP aligns well with real-world problem-solving by modeling systems as objects with specific behaviors and attributes. This approach makes it easier to translate real-world scenarios into code.
Supports Software Evolution: OOP's flexibility allows for easier adaptation to changing requirements and technological advancements. It enables developers to introduce new features or modify existing ones without disrupting the entire codebase.
Conclusion
Object-Oriented Programming (OOP) in Java is more than syntax—it's a mindset that fosters modular, reusable code. By organizing around objects, it simplifies maintenance, encourages scalability, and boosts security through encapsulation.
Mastering OOP principles empowers developers to build adaptable, elegant solutions. Embrace this paradigm, apply it in your projects, and let it guide your journey in Java programming. OOP isn't just a toolkit; it's a powerful approach to crafting resilient and efficient software. Keep coding, keep innovating, and let OOP be your compass in the dynamic world of Java development.
Subscribe to my newsletter
Read articles from Jonayed Baperi directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Jonayed Baperi
Jonayed Baperi
Hey, I'm Jonayed, a devoted developer with two years' experience crafting tech solutions. I thrive on tackling complex challenges and eagerly adopt new technologies. Driven by an insatiable thirst for learning, I relish mastering emerging tech to stay ahead in this dynamic field. I'm more than code – I'm an enthusiastic blogger. Through my articles, I share tech insights, problem-solving methods, and personal experiences. Join me as I document my continuous exploration in the vast tech universe. Let's connect, learn, and grow together!