Composition vs Inheritance
Part of the Object Oriented Programming section of Coddy's Java journey — lesson 47 of 87.
Inheritance creates an "is-a" relationship: a Dog is an Animal. But what if a class needs functionality from something it isn't? This is where composition comes in, establishing a "has-a" relationship instead.
With composition, a class contains instances of other classes as fields rather than extending them:
// Inheritance approach: Car IS an Engine (doesn't make sense)
class Car extends Engine { }
// Composition approach: Car HAS an Engine (makes sense)
class Car {
private Engine engine;
public Car(Engine engine) {
this.engine = engine;
}
public void start() {
engine.ignite();
}
}Composition offers several advantages. You can change the composed object at runtime, such as swapping engines.
You can also combine behaviors from multiple classes, something inheritance doesn't allow in Java. The composed class only exposes the methods it chooses, providing better encapsulation.
A practical guideline: use inheritance when there's a genuine "is-a" relationship and the subclass truly represents a specialized version of the parent.
Use composition when you need to use another class's functionality without being that type. Many experienced developers follow the principle: "favor composition over inheritance" because it leads to more flexible, maintainable code.
Challenge
EasyLet's build a computer system using composition to demonstrate the "has-a" relationship. Instead of a Computer inheriting from its components (which wouldn't make sense), your computer will contain the parts it needs to function.
You'll organize your code across three files:
Processor.java: Create a class representing a CPU. A Processor has two private fields:brand(String) andspeedGHz(double). Include a constructor to initialize both fields and getter methods for each. Add aprocess()method that returns a String:[brand] processing at [speedGHz] GHzMemory.java: Create a class representing RAM. A Memory has two private fields:type(String, like "DDR4" or "DDR5") andsizeGB(int). Include a constructor, getters, and aload()method that returns:Loading [sizeGB]GB [type] memoryComputer.java: Here's where composition shines! Your Computer class should have a Processor and a Memory as private fields—it doesn't extend them, it contains them. Include a constructor that accepts both components. Add aboot()method that returns a multi-line String showing the computer starting up by using its components:Also add aBooting computer... [processor.process() result] [memory.load() result] System ready!getSpecs()method that returns:Specs: [processor brand] CPU, [memory sizeGB]GB [memory type]Main.java: Bring your composed system to life! You'll receive four inputs: processor brand (String), processor speed (double), memory type (String), and memory size (int).Create a Processor and Memory with these values, then compose them into a Computer. Print the result of calling
boot(), then print the result ofgetSpecs().
You will receive four inputs in order: processor brand, processor speed (GHz), memory type, and memory size (GB).
Notice how the Computer delegates work to its components rather than trying to be them—this is the power of composition! The Computer can use any Processor or Memory you give it, making the design flexible and realistic.
Cheat sheet
Composition creates a "has-a" relationship where a class contains instances of other classes as fields rather than extending them.
Inheritance vs Composition:
// Inheritance: Car IS an Engine (doesn't make sense)
class Car extends Engine { }
// Composition: Car HAS an Engine (makes sense)
class Car {
private Engine engine;
public Car(Engine engine) {
this.engine = engine;
}
public void start() {
engine.ignite();
}
}Advantages of Composition:
- Objects can be changed at runtime
- Can combine behaviors from multiple classes
- Better encapsulation - only expose chosen methods
- More flexible and maintainable code
When to Use:
- Inheritance: Use when there's a genuine "is-a" relationship and the subclass is a specialized version of the parent
- Composition: Use when you need another class's functionality without being that type
Best Practice: "Favor composition over inheritance"
Try it yourself
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Read inputs
String processorBrand = scanner.nextLine();
double processorSpeed = Double.parseDouble(scanner.nextLine());
String memoryType = scanner.nextLine();
int memorySize = Integer.parseInt(scanner.nextLine());
// TODO: Create a Processor with the brand and speed
// TODO: Create a Memory with the type and size
// TODO: Create a Computer by composing the Processor and Memory
// TODO: Print the result of boot()
// TODO: Print the result of getSpecs()
}
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesIntroduction to OOPClasses vs ObjectsThe this KeywordMethodsFields (Attributes)Constructor MethodConstructor OverloadingRecap - Simple Calculator4Inheritance
Basic Inheritance (extends)The super KeywordMethod Overriding (@Override)Constructor ChainingThe Object ClassSingle & Multilevel InheritWhy No Multi Class InheritRecap - Employee Hierarchy7Special Methods & Object Class
toString() Methodequals() and hashCode()clone() MethodcompareTo() and ComparableComparator InterfaceRecap - Custom Sorting2Access Modifiers & Encapsulate
Access Levels OverviewGetter and Setter MethodsInformation HidingThe final KeywordRecap - Bank Account Manager5Polymorphism
Method Overloading BasicsMethod Overriding (Run-Time)Upcasting and DowncastingThe instanceof OperatorAbstract Classes and MethodsRecap - Shape Calculator8Advanced OOP Concepts
Composition vs InheritanceAggregation vs CompositionInner Nested & Anonymous ClassEnums and Enum MethodsRecords (Java 16+)Sealed Classes (Java 17+)3Class Props & Static Member
Instance vs Static VariablesStatic MethodsStatic BlocksConstants (static final)Recap - Counter & Utility6Interfaces & Abstract Classes
Introduction to InterfacesImplementing InterfacesMulti Interface ImplemenDefault & Static in InterfaceAbstract Classes vs InterfacesFunctional InterfacesRecap - Payment System