Code360 powered by Coding Ninjas X Naukri.com. Code360 powered by Coding Ninjas X Naukri.com
Table of contents
1.
Introduction
2.
Composition in Java
3.
Key Points of Composition in Java
4.
Example 
4.1.
Java
5.
Benefits of Using Composition in Java
5.1.
Java
6.
Frequently Asked Questions
6.1.
What is the main difference between composition and inheritance in Java?
6.2.
Can composition replace inheritance in Java?
6.3.
When should I use composition over inheritance in Java?
7.
Conclusion
Last Updated: May 25, 2024

Composition in Java

Author Riya Singh
0 upvote
Crack Google SDE interview : Essential projects
Speaker
Saurav Prateek
SDE-2 @
20 Jun, 2024 @ 01:30 PM

Introduction

Composition is a fundamental concept in object-oriented programming (OOP) that allows objects to contain other objects as part of their state. In Java, composition is achieved by including an instance of one class within another class. This powerful technique enables code reuse, flexibility & helps in designing clear, modular programs. 

Composition in Java

In this article, we'll learn about the key points of composition in Java, examples & discuss the benefits of using this approach in your code.

Composition in Java

In Java, composition is a design technique where a class includes an instance of another class as a field, rather than inheriting from it. The containing class is said to have a "has-a" relationship with the contained class. For example, a Car class could have a composition relationship with an Engine class, since a car "has an" engine. This allows the Car class to reuse the functionality of the Engine class without using inheritance.

Here's a simple code example to illustrate composition:

class Engine {
    void startEngine() {
        System.out.println("Engine started.");
    }
}

class Car {
    private Engine engine;
    Car() {
        engine = new Engine();
    }
    void start() {
        engine.startEngine();
    }
}


In this example, the Car class contains an instance of the Engine class as a private field. The Car constructor initializes the Engine object, & the start() method of Car calls the startEngine() method of the Engine instance.

Get the tech career you deserve, faster!
Connect with our expert counsellors to understand how to hack your way to success
User rating 4.7/5
1:1 doubt support
95% placement record
Akash Pal
Senior Software Engineer
326% Hike After Job Bootcamp
Himanshu Gusain
Programmer Analyst
32 LPA After Job Bootcamp
After Job
Bootcamp

Key Points of Composition in Java

Composition in Java is a design technique where one object is composed of one or more instances of other objects. Essentially, it implements a "has-a" relationship. For example, a Library class might have a List of Book objects, indicating that a library contains books but is not a type of book. This relationship is useful for several reasons:

  • Composition allows a class to contain an instance of another class as a member field, establishing a "has-a" relationship between the classes.
     
  • The containing class can use the methods & properties of the contained class, promoting code reuse & modularity.
     
  • Composition is a more flexible alternative to inheritance, as it allows a class to use functionality from multiple classes without the restrictions of single inheritance in Java.
     
  • The contained object is typically declared as a private field in the containing class, ensuring encapsulation & preventing direct access from outside the class.
     
  • The containing class can initialize the contained object in its constructor or provide setter methods to assign the object later.
     
  • Composition allows for more control over the visibility & accessibility of the contained object, as the containing class can expose only the necessary methods & properties.
     
  • Composition can be used to represent relationships where the contained object is a part or component of the containing object, such as a car having an engine or a computer having a processor.
     
  • Composition helps in creating more maintainable & loosely coupled code, as changes to the contained class don't directly affect the containing class, as long as the interface remains the same.

Example 

  • Java

Java

class Engine {
void start() {
System.out.println("Engine Starting...");
}

void stop() {
System.out.println("Engine Stopping...");
}
}

class Car {
// The Car "has-a" Engine.
private Engine engine;

Car() {
this.engine = new Engine();
}

void startCar() {
engine.start();
System.out.println("Car is running");
}

void stopCar() {
engine.stop();
System.out.println("Car has stopped");
}
}

public class Main {
public static void main(String[] args) {
Car myCar = new Car();
myCar.startCar();
myCar.stopCar();
}
}

Output

Engine Starting...
Car is running
Engine Stopping...
Car has stopped


In this example, the Car class is composed of the Engine class. The Car class does not inherit the properties of Engine but rather contains an Engine. This setup shows how composition is used to encapsulate behaviors in Java, making objects operate through their contained instances.

Benefits of Using Composition in Java

  1. Code reuse: Composition allows you to reuse code from other classes without the need for inheritance. By including instances of other classes as member fields, you can utilize their functionality in your class, leading to more modular & reusable code.
     
  2. Flexibility: Composition provides more flexibility than inheritance, as a class can include multiple instances of different classes. This allows you to combine functionality from various classes as needed, without being limited by the single inheritance restriction in Java.
     
  3. Loose coupling: Composition promotes loose coupling between classes, as the containing class is not tightly bound to the implementation of the contained class. This makes the code more maintainable, as changes to the contained class don't directly affect the containing class, as long as the interface remains the same.
     
  4. Encapsulation: Composition allows for better encapsulation, as the contained objects are typically declared as private fields in the containing class. This encapsulation prevents direct access to the contained objects from outside the class, providing better control over the visibility & accessibility of the contained objects.
     
  5. Clarity & readability: Composition helps in creating clearer & more readable code by breaking down complex systems into smaller, more manageable parts. Each class can focus on a specific responsibility, making the overall design easier to understand & maintain.
     
  6. Testability: Composition enhances the testability of code, as each class can be tested independently. The containing class can be tested using mock objects for the contained classes, allowing for more focused & isolated unit testing.
     
  7. Runtime flexibility: Composition allows for runtime flexibility, as the contained objects can be assigned or changed dynamically during program execution. This enables more dynamic & adaptable behavior in your programs.
     

For instance, consider an application that models a zoo which includes various types of animals. Instead of creating separate classes for each animal that inherits from a base class, you could have a class Animal with a composition of different behavior objects such as Walking, Flying, and Swimming. Depending on the animal, appropriate behaviors can be composed dynamically:

  • Java

Java

class Walking {
void walk() {
System.out.println("This animal walks.");
}
}

class Flying {
void fly() {
System.out.println("This animal flies.");
}
}

class Animal {
private Walking walking;
private Flying flying;

public Animal(Walking walking, Flying flying) {
this.walking = walking;
this.flying = flying;
}

void performWalk() {
if (walking != null) {
walking.walk();
}
}

void performFly() {
if (flying != null) {
flying.fly();
}
}
}

public class Zoo {
public static void main(String[] args) {
Animal eagle = new Animal(null, new Flying());
Animal elephant = new Animal(new Walking(), null);

eagle.performFly();
elephant.performWalk();
}
}

Output

This animal flies.
This animal walks.


In this scenario, the Animal class uses composition to adapt to various types of animal behaviors, enhancing flexibility and reusability of the behavior classes without inheriting from them.

Frequently Asked Questions

What is the main difference between composition and inheritance in Java?

Composition involves creating objects which contain other objects, while inheritance is about creating a new class that inherits properties & behaviors from an existing class. Composition uses a "has-a" relationship, and inheritance uses an "is-a" relationship.

Can composition replace inheritance in Java?

Yes, in many cases, composition can be used as an alternative to inheritance, especially to overcome problems like excessive coupling and deep inheritance hierarchies that can make maintenance difficult.

When should I use composition over inheritance in Java?

You should consider using composition when you need to change the components' behavior dynamically at runtime, or when you see that using inheritance could lead to an unnecessarily complex class structure. It's also recommended when you want to maintain high levels of encapsulation and modularity in your application.

Conclusion

In this article, we have learned about composition in Java, a useful and importantly versatile design principle that favors using object references to include functionalities from other classes rather than inheriting from them. We learned its key benefits, such as improved encapsulation, reduced complexity, increased flexibility, avoidance of inheritance drawbacks, and greater reusability. 

You can refer to our guided paths on the Coding Ninjas. You can check our course to learn more about DSADBMSCompetitive ProgrammingPythonJavaJavaScript, etc. Also, check out some of the Guided Paths on topics such as Data Structure andAlgorithmsCompetitive ProgrammingOperating SystemsComputer Networks, DBMSSystem Design, etc., as well as some Contests, Test Series, and Interview Experiences curated by top Industry Experts.

Previous article
Modulo or Remainder Operator in Java
Next article
Process vs Thread in Java
Live masterclass