Contents
Inheritance
Inheritance and Constructors
In Java, constructors are used to initialize the attributes of an object, making the language more reflective of real-world scenarios. By default, Java provides a no-argument constructor that is automatically invoked if no constructors are defined. However, if you create a custom constructor, such as a parameterized one, you must explicitly define the default constructor, as it will no longer be provided automatically.
Note:
If a base class has a no-argument constructor, it is called automatically when a constructor of the derived class is invoked.
Example:
// Java Program to Demonstrate
// Constructor Invocation Without Using super Keyword
// Parent class
class Parent {
// Constructor of the parent class
Parent() {
System.out.println("Parent Class Constructor Called");
}
}
// Child class
class Child extends Parent {
// Constructor of the child class
Child() {
System.out.println("Child Class Constructor Called");
}
}
// Main class
public class Main {
public static void main(String[] args) {
// Creating an object of the child class
Child childObj = new Child();
// Note: The constructor of the parent class is invoked first,
// followed by the constructor of the child class.
}
}
Output:
Parent Class Constructor Called
Child Class Constructor Called
Note:
If a base class has a no-argument constructor, it is called automatically when a constructor of the derived class is invoked.
Example:
// Java Program to Demonstrate
// Constructor Invocation Using super Keyword
// Base class
class Vehicle {
int speed;
// Parameterized constructor of the base class
Vehicle(int spd) {
speed = spd;
}
}
// Subclass
class Car extends Vehicle {
String model;
// Constructor of the subclass
Car(int spd, String mdl) {
// Using super to call the base class constructor
super(spd);
model = mdl;
}
// Method to display details
void displayDetails() {
System.out.println("Speed: " + speed + ", Model: " + model);
}
}
// Main class
public class Main {
public static void main(String[] args) {
// Creating an object of the subclass
Car carObj = new Car(120, "Sedan");
// Displaying details of the car
carObj.displayDetails();
}
}
Output:
Speed: 120, Model: Sedan
Explanation:
In this example, the super()
keyword is used to call the base class (Vehicle
) constructor with a parameter (speed
). This call must be the first statement in the subclass (Car
) constructor. Afterward, the model
attribute is initialized, and the displayDetails()
method prints the values of speed
and model
.
Key Points:
- The base class constructor is always called before the subclass constructor.
- The
super()
keyword is used to explicitly invoke the base class constructor and must be the first line in the subclass constructor. - If
super()
is not used, the default constructor of the base class is invoked automatically.
Multiple Inheritance
Multiple inheritance is an object-oriented concept where a class can inherit from more than one parent class. However, a problem arises when both parent classes have methods with the same signature. In such cases, the compiler is unable to decide which method to execute, leading to ambiguity. Java avoids these complexities by not supporting multiple inheritance through classes.
Note:
Java does not support multiple inheritance through classes, but it handles this scenario for interfaces using default methods introduced in Java 8.
Example 1:
// Java Program to Demonstrate Lack of Support for Multiple Inheritance
// First parent class
class Parent1 {
void display() {
System.out.println("Parent1");
}
}
// Second parent class
class Parent2 {
void display() {
System.out.println("Parent2");
}
}
// Class trying to inherit from both Parent1 and Parent2 (Invalid)
class Child extends Parent1, Parent2 {
public static void main(String[] args) {
Child obj = new Child();
obj.display(); // Ambiguity issue
}
}
Output:
Compilation Error
Explanation:
Java does not support multiple inheritance using classes. If you try to inherit from both Parent1
and Parent2
, the compiler will throw an error because it cannot determine which display()
method to call.
How Java Handles Multiple Inheritance with Interfaces
While Java doesn’t allow multiple inheritance through classes, it allows it through interfaces. Java 8 introduced default methods, which allow interfaces to provide default implementations of methods. If a class implements multiple interfaces with default methods that have the same signature, it must resolve the conflict by overriding the method.
Example 2: Handling Multiple Inheritance with Interfaces
// Interface 1
interface Interface1 {
default void show() {
System.out.println("Default Interface1");
}
}
// Interface 2
interface Interface2 {
default void show() {
System.out.println("Default Interface2");
}
}
// Implementation class that implements both interfaces
class MyClass implements Interface1, Interface2 {
// Overriding the show method to resolve ambiguity
@Override
public void show() {
Interface1.super.show(); // Explicitly calling Interface1's show method
Interface2.super.show(); // Explicitly calling Interface2's show method
}
// Methods to call specific interface methods
public void showInterface1() {
Interface1.super.show();
}
public void showInterface2() {
Interface2.super.show();
}
public static void main(String[] args) {
MyClass obj = new MyClass();
obj.show(); // Resolving ambiguity
System.out.println("Calling individual interface methods:");
obj.showInterface1();
obj.showInterface2();
}
}
Output:
Default Interface1
Default Interface2
Calling individual interface methods:
Default Interface1
Default Interface2
Explanation:
In this example, MyClass
implements both Interface1
and Interface2
, which both have a default show()
method. By overriding the show()
method in MyClass
, we use Interface1.super.show()
and Interface2.super.show()
to specify which interface’s method to call. Additionally, the class provides methods to call individual interface methods if needed.
Example 3: Diamond Problem with Default Methods in Interfaces
// Root interface with a default method
interface RootInterface {
default void display() {
System.out.println("Default RootInterface");
}
}
// First child interface extending RootInterface
interface ChildInterface1 extends RootInterface {
}
// Second child interface extending RootInterface
interface ChildInterface2 extends RootInterface {
}
// Class implementing both child interfaces
class MyClass implements ChildInterface1, ChildInterface2 {
public static void main(String[] args) {
MyClass obj = new MyClass();
obj.display(); // No ambiguity, RootInterface's method is called
}
}
Output:
Default RootInterface
Explanation:
In this case, both ChildInterface1
and ChildInterface2
extend the same RootInterface
, which has a default display()
method. Since neither ChildInterface1
nor ChildInterface2
overrides the method, there is no ambiguity, and the RootInterface
method is called directly.
Interfaces and Inheritance in Java
In Java, a class can extend another class and implement one or more interfaces. This relationship has a significant role in understanding Java’s approach to Multiple Inheritance.
Key Concepts:
1. Inheritance Hierarchy: Java enforces a clear hierarchy, where a class can inherit from another class using the extends
keyword, and implement interfaces using the implements
keyword. The hierarchy cannot be reversed; that is, a class cannot extend an interface, as doing so would violate the core principles of class-based inheritance.
Example of Class Implementing Multiple Interfaces
// Java program to demonstrate that a class can
// implement multiple interfaces
interface InterfaceA {
void method1();
}
interface InterfaceB {
void method2();
}
// class implements both interfaces
// and provides implementation for the methods
class ExampleClass implements InterfaceA, InterfaceB {
@Override
public void method1() {
System.out.println("Executing method1 from InterfaceA");
}
@Override
public void method2() {
System.out.println("Executing method2 from InterfaceB");
}
}
public class Main {
public static void main(String[] args) {
ExampleClass obj = new ExampleClass();
// calling the methods implemented in the class
obj.method1();
obj.method2();
}
}
2. Interface Inheritance: In Java, an interface can extend another interface, allowing for inheritance of method signatures, which can later be implemented in classes.
Example of Interface Inheritance
// Interface inheritance demonstration
interface InterfaceA {
void display();
}
interface InterfaceB extends InterfaceA {
void show();
}
class DemoClass implements InterfaceB {
@Override
public void display() {
System.out.println("Display method from InterfaceA");
}
@Override
public void show() {
System.out.println("Show method from InterfaceB");
}
}
public class Main {
public static void main(String[] args) {
DemoClass obj = new DemoClass();
obj.display();
obj.show();
}
}
Output:
Display method from InterfaceA
Show method from InterfaceB
Types of Inheritance in Java
Java supports different types of inheritance, such as single, multilevel, and hierarchical inheritance, while restricting multiple and hybrid inheritance through interfaces.
1. Single Inheritance: When a class inherits from only one superclass.
class A {
int num1;
void setNum1(int x) {
num1 = x;
}
}
class B extends A {
int num2;
void setNum2(int y) {
num2 = y;
}
void displayProduct() {
System.out.println("Product: " + (num1 * num2));
}
}
public class Main {
public static void main(String[] args) {
B obj = new B();
obj.setNum1(3);
obj.setNum2(4);
obj.displayProduct();
}
}
Output:
Product: 12
2. Multilevel Inheritance: Involves a chain of inheritance where a class is derived from another derived class.
class A {
int num1;
void setNum1(int x) {
num1 = x;
}
}
class B extends A {
int num2;
void setNum2(int y) {
num2 = y;
}
}
class C extends B {
void displaySum() {
System.out.println("Sum: " + (num1 + num2));
}
}
public class Main {
public static void main(String[] args) {
C obj = new C();
obj.setNum1(5);
obj.setNum2(10);
obj.displaySum();
}
}
Output:
Sum: 15
3. Hierarchical Inheritance: Multiple classes inherit from the same superclass.
class A {
void greet() {
System.out.println("Hello from Class A");
}
}
class B extends A {
void greetFromB() {
System.out.println("Greetings from Class B");
}
}
class C extends A {
void greetFromC() {
System.out.println("Greetings from Class C");
}
}
public class Main {
public static void main(String[] args) {
B objB = new B();
C objC = new C();
objB.greet();
objB.greetFromB();
objC.greet();
objC.greetFromC();
}
}
Output:
Hello from Class A
Greetings from Class B
Hello from Class A
Greetings from Class C
Inheritance in Interfaces
Java interfaces can inherit from multiple interfaces, enabling classes to implement complex behavior while avoiding ambiguity.
Example of Multiple Interface Inheritance
interface InterfaceX {
void displayName();
}
interface InterfaceY {
void displayDepartment();
}
interface InterfaceZ extends InterfaceX, InterfaceY {
void displayRole();
}
class Employee implements InterfaceZ {
@Override
public void displayName() {
System.out.println("Employee Name: John");
}
@Override
public void displayDepartment() {
System.out.println("Department: IT");
}
@Override
public void displayRole() {
System.out.println("Role: Developer");
}
public static void main(String[] args) {
Employee emp = new Employee();
emp.displayName();
emp.displayDepartment();
emp.displayRole();
}
}
Output:
Employee Name: John
Department: IT
Role: Developer
Association, Composition and Aggregation in Java
In object-oriented programming, relationships between classes are fundamental for defining interactions between objects. Java, as an object-oriented language, allows modeling these relationships using association, aggregation, and composition. These concepts describe how instances of classes relate and interact with one another.
Association
Association represents a general relationship between two independent classes, where one class may use or interact with another. This relationship can be one-to-one, one-to-many, many-to-one, or many-to-many, without implying ownership. Classes in association are independent of each other.
Types of Association
-
Unidirectional Association: One class knows and interacts with another, but the reverse is not true. For example, a
Customer
class may be associated with anOrder
class, but theOrder
class does not need to be aware of theCustomer
. -
Bidirectional Association: Both classes are aware of and interact with each other. For example, a
Player
class and aTeam
class might be associated in a bidirectional relationship, where a player belongs to a team, and the team knows which players are on it.
Example of Association:
// Java program illustrating Association
import java.util.*;
class Library {
private String libraryName;
private Set books;
public Library(String libraryName) {
this.libraryName = libraryName;
}
public String getLibraryName() {
return this.libraryName;
}
public void setBooks(Set books) {
this.books = books;
}
public Set getBooks() {
return this.books;
}
}
class Book {
private String title;
public Book(String title) {
this.title = title;
}
public String getTitle() {
return this.title;
}
}
public class AssociationExample {
public static void main(String[] args) {
// Creating Book objects
Book book1 = new Book("Java Basics");
Book book2 = new Book("Advanced Java");
// Adding books to a set
Set bookSet = new HashSet<>();
bookSet.add(book1);
bookSet.add(book2);
// Creating a Library object
Library library = new Library("City Library");
// Setting books for the library
library.setBooks(bookSet);
// Displaying library books
for (Book book : library.getBooks()) {
System.out.println(book.getTitle() + " is available at " + library.getLibraryName());
}
}
}
Output:
Java Basics is available at City Library
Advanced Java is available at City Library
In this example, the Library
and Book
classes are associated, where a library contains multiple books, forming a one-to-many relationship.
Aggregation
Aggregation is a specialized form of association that represents a “has-a” relationship. In aggregation, one class (the whole) contains other classes (the parts), but the lifecycle of the parts is independent of the whole. For instance, a University
may contain multiple Department
s, but a department can exist independently of the university.
Example of Aggregation:
// Java program illustrating Aggregation
import java.util.*;
class Course {
private String courseName;
private int courseId;
public Course(String courseName, int courseId) {
this.courseName = courseName;
this.courseId = courseId;
}
public String getCourseName() {
return this.courseName;
}
public int getCourseId() {
return this.courseId;
}
}
class Department {
private String deptName;
private List courses;
public Department(String deptName, List courses) {
this.deptName = deptName;
this.courses = courses;
}
public List getCourses() {
return this.courses;
}
}
class University {
private String universityName;
private List departments;
public University(String universityName, List departments) {
this.universityName = universityName;
this.departments = departments;
}
public int getTotalCoursesInUniversity() {
int totalCourses = 0;
for (Department dept : departments) {
totalCourses += dept.getCourses().size();
}
return totalCourses;
}
}
public class AggregationExample {
public static void main(String[] args) {
// Creating Course objects
Course c1 = new Course("Data Structures", 101);
Course c2 = new Course("Algorithms", 102);
Course c3 = new Course("Operating Systems", 103);
// Creating lists of courses
List csCourses = Arrays.asList(c1, c2);
List itCourses = Arrays.asList(c3);
// Creating Department objects
Department csDept = new Department("Computer Science", csCourses);
Department itDept = new Department("Information Technology", itCourses);
// Creating a list of departments
List departments = Arrays.asList(csDept, itDept);
// Creating a University object
University university = new University("Tech University", departments);
// Printing total courses in university
System.out.println("Total courses in university: " + university.getTotalCoursesInUniversity());
}
}
Output:
Total courses in university: 3
In this example, a university contains multiple departments, each having courses. The university and department are in an aggregation relationship, where departments can exist independently of the university.
Composition
Composition is a strong form of association where the lifecycle of the contained objects is dependent on the container object. If the container object is destroyed, the contained objects are also destroyed. This represents a “part-of” relationship, like a Car
and its Engine
. If the car is destroyed, the engine also ceases to exist.
Example of Composition:
// Java program illustrating Composition
import java.util.*;
class Engine {
private String engineType;
public Engine(String engineType) {
this.engineType = engineType;
}
public String getEngineType() {
return this.engineType;
}
}
class Car {
private String carName;
private Engine engine;
public Car(String carName, String engineType) {
this.carName = carName;
this.engine = new Engine(engineType); // Composition
}
public String getCarDetails() {
return this.carName + " has an engine of type " + engine.getEngineType();
}
}
public class CompositionExample {
public static void main(String[] args) {
// Creating a Car object with composition
Car car = new Car("Tesla", "Electric");
// Displaying car details
System.out.println(car.getCarDetails());
}
}
Output:
Tesla has an engine of type Electric
In this example, the Car
and Engine
have a composition relationship. The Engine
cannot exist without the Car
, representing strong ownership.
Key Differences Between Association, Aggregation, and Composition
Feature | Association | Aggregation | Composition |
---|---|---|---|
Definition | General relationship between two classes | “Has-a” relationship | “Part-of” relationship |
Dependency | Classes can exist independently | Parts can exist independently of the whole | Parts depend on the whole |
Lifecycle | Independent lifecycles | Independent lifecycles | Dependent lifecycles |
Ownership | No ownership implied | Shared ownership | Exclusive ownership |
Strength | Weak | Moderate | Strong |
These relationships play a key role in designing well-structured, reusable, and maintainable software systems.