Inheritance is one of fundamental concept in java, allowing a class to inherit properties and behaviors from another class. It enables code reuse and promotes a hierarchical structure among classes.
Importance/Advanges of Inheritance in Java:
Code Reusability:
It allows subclasses to inherit methods and fields from a superclass, reducing redundant code.
Modularity:
It promotes modularity by organizing classes in a hierarchical structure, making the code easier to understand and maintain.
Polymorphism:
It facilitates polymorphism, where objects of subclasses can be treated as objects of their superclass, enabling dynamic method invocation.
Types of Inheritance Supported by Java:
Single Inheritance:
A subclass can inherit from only one superclass.
Multilevel Inheritance:
A class can inherit from another class, and that class can further inherit from another class, creating a chain of inheritance.
Hierarchical Inheritance:
Multiple subclasses inherit from a single superclass.
Multiple Inheritance:
Due to the diamond problem, Java does not support multiple inheritance. Java is uses inheritance for making code easy and reuses not to make complex therefore java does not support direct multiple inheritance.
Reason for Not Supporting Multiple Inheritance in Java:
Java intentionally avoids multiple inheritance of classes to prevent the diamond problem, where ambiguity arises if a subclass inherits from multiple superclasses with conflicting implementations. However, Java supports multiple inheritance through interfaces, where a class can implement multiple interfaces, each defining a set of methods without the risk of conflicts.
Scenarios and Examples:
For Importance, at least two classes required. One parent class which is already exist and another child class that we want to create with help of parent class.
Let's illustrate these concepts with examples:
Single Inheritance:
One child class inherits one parent class. Car inherits Vehicle class.
// Example of Single Inheritance
class Vehicle {
void start() {
System.out.println("Vehicle started.");
}
}
class Car extends Vehicle {
void drive() {
System.out.println("Car is being driven.");
}
}
public class Main {
public static void main(String[] args) {
Car car = new Car();
car.start(); // Output: Vehicle started.
car.drive(); // Output: Car is being driven.
}
}
Use Case:
Person is a class having common properties(id, firstName, lastName,contactNumber).
Player is a class type of Person playing game. Find out what kind of player is some one based on year of experience.
experience < 1 Beginner
experience < 3 Intermediate
experience >= 3 Expert
Otherwise Invalid number of year experience.
Outlines for solution:
Parent Class: Person
Properties:
id, firstName, lastName,contactNumber
Methods:
constructor
setter/getter
toString
Child Class: Player
Properties:
game
experience
Methods:
constructor
setter/getter
toString
calcPlayerType(experience)
Solution Code:
package com.game;
public class Person {
private int id;
private String firstName;
private String lastName;
private long contactNumber;
private static int generatedId=100;
public Person(String firstName, String lastName,
long contactNumber) {
this.id = ++generatedId;
this.firstName = firstName;
this.lastName = lastName;
this.contactNumber = contactNumber;
}
public int getId() {
return id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public long getContactNumber() {
return contactNumber;
}
public void setContactNumber(long contactNumber) {
this.contactNumber = contactNumber;
}
@Override
public String toString() {
return id +
", " + firstName +
", " + lastName +
", " + contactNumber;
}
}
package com.game;
public class Player extends Person {
private String game;
private int experience;
public Player(String firstName, String lastName,
long contactNumber, String game, int experience) {
super(firstName, lastName, contactNumber);
this.game = game;
this.experience = experience;
}
public String getGame() {
return game;
}
public void setGame(String game) {
this.game = game;
}
public int getExperience() {
return experience;
}
public void setExperience(int experience) {
this.experience = experience;
}
@Override
public String toString() {
return "Player{" + " "+
super.toString()+
"game='" + game +
", experience=" + experience +
"Player type="+ calcPlayerType();
}
String calcPlayerType() {
String gameLevel = null;
if (experience < 1) {
gameLevel = "Beginner";
} else if (experience >= 1 && experience < 3) {
gameLevel = "Intermediate";
return gameLevel;
} else if (experience >= 3) {
gameLevel = "Expert";
} else {
gameLevel= "not valid";
}
return gameLevel;
}
}
package com.game;
public class Main {
public static void main(String[] args) {
//upcasting
Person person=new Player("Ramya","Singh",9818254421l,
"Cricket",2);
System.out.println(person);
//downcasting
Player player=(Player) person;
player.setExperience(5);
player.setLastName("Sharma");
System.out.println(person);
Player player2=new Player("Sarita","Kumari",8587001003l,
"Football",1);
player2.setExperience(5);
System.out.println(player2);
}
}
Multilevel Inheritance: When child class also become parent of some other class is known as Multilevel Inheritance. Animal to Dog and Dog to also BullDog.
// Example of Multilevel Inheritance
class Animal {
void eat() {
System.out.println("Animal is eating.");
}
}
class Dog extends Animal {
void bark() {
System.out.println("Dog is barking.");
}
}
class BullDog extends Dog {
void guard() {
System.out.println("Bulldog is guarding.");
}
}
public class Main {
public static void main(String[] args) {
BullDog bulldog = new BullDog();
bulldog.eat(); // Output: Animal is eating.
bulldog.bark(); // Output: Dog is barking.
bulldog.guard(); // Output: Bulldog is guarding.
}
}
Hierarchical Inheritance: When multiple child classes inherits properties/methods of single base/paret class. As child classes Circle and Rectangle are inheriting Shape as parent class.
// Example of Hierarchical Inheritance
class Shape {
void draw() {
System.out.println("Drawing a shape.");
}
}
class Circle extends Shape {
void draw() {
System.out.println("Drawing a circle.");
}
}
class Rectangle extends Shape {
void draw() {
System.out.println("Drawing a rectangle.");
}
}
public class Main {
public static void main(String[] args) {
Circle circle = new Circle();
circle.draw(); // Output: Drawing a circle.
Rectangle rectangle = new Rectangle();
rectangle.draw(); // Output: Drawing a rectangle.
}
}
Multiple Inheritance: It does not directly supported by Java. If it is required then we can achieve indirect inheritance in form of contract(Interface).
// Example of Multiple Inheritance indirectly through Interfaces
interface Jumpable {
void jump();
}
interface Runnable {
void run();
}
class Athlete implements Jumpable, Runnable {
public void jump() {
System.out.println("Athlete jumps.");
}
public void run() {
System.out.println("Athlete runs.");
}
}
public class Main {
public static void main(String[] args) {
Athlete athlete = new Athlete();
athlete.jump(); // Output: Athlete jumps.
athlete.run(); // Output: Athlete runs.
}
}
Use Case:
Account class is the superclass which contains common attributes(accountNumber,balance) and methods related to bank accounts(setters/getters, toString, deposite and withdraw). SavingAccount and RecurringAccount are subclasses that inherit from Account.
SavingAccount has an additional attribute interestRate and a method addInterest() to add interest to the balance.
RecurringAccount has an additional attribute monthlyDeposit and a method depositMonthly() to add monthly deposits to the balance.
In the MainMethodClass class, create instances of SavingAccount and RecurringAccount and call their respective methods to perform transactions specific to each type of account.
// Account.java
public class Account {
private String accountNumber;
private double balance;
public Account(String accountNumber, double balance) {
this.accountNumber = accountNumber;
this.balance = balance;
}
public String getAccountNumber() {
return accountNumber;
}
public double getBalance() {
return balance;
}
public void deposit(double amount) {
balance += amount;
System.out.println("Deposited: " + amount);
}
public void withdraw(double amount) {
if (balance >= amount) {
balance -= amount;
System.out.println("Withdrawn: " + amount);
} else {
System.out.println("Insufficient balance");
}
}
}
// SavingAccount.java
public class SavingAccount extends Account {
private double interestRate;
public SavingAccount(String accountNumber, double balance, double interestRate) {
super(accountNumber, balance);
this.interestRate = interestRate;
}
public double getInterestRate() {
return interestRate;
}
public void addInterest() {
double interest = getBalance() * interestRate / 100;
deposit(interest);
System.out.println("Interest added: " + interest);
}
}
// RecurringAccount.java
public class RecurringAccount extends Account {
private double monthlyDeposit;
public RecurringAccount(String accountNumber, double balance, double monthlyDeposit) {
super(accountNumber, balance);
this.monthlyDeposit = monthlyDeposit;
}
public double getMonthlyDeposit() {
return monthlyDeposit;
}
public void depositMonthly() {
deposit(monthlyDeposit);
System.out.println("Monthly deposit added: " + monthlyDeposit);
}
}
// MainMethodClass.java
public class MainMethodClass {
public static void main(String[] args) {
SavingAccount savingAccount = new SavingAccount("SA001", 5000, 5);
RecurringAccount recurringAccount = new RecurringAccount("RA001", 3000, 1000);
// Deposit to saving account and add interest
savingAccount.deposit(2000);
savingAccount.addInterest();
System.out.println("Saving Account Balance: " + savingAccount.getBalance());
// Deposit to recurring account and add monthly deposit
recurringAccount.deposit(1500);
recurringAccount.depositMonthly();
System.out.println("Recurring Account Balance: " + recurringAccount.getBalance());
}
}
Try Now Following Assignments:
Use Case 1:
Implement a Shape hierarchy with classes Rectangle and Circle. Calculate the area and perimeter of each shape.
Test Cases:
Create a Rectangle with width 5 and height 4, verify its area is 20 and perimeter is 18.
Create a Circle with radius 3, verify its area is approximately 28.27 and perimeter is approximately 18.85.
Use Case 2:
Create a hierarchy of vehicles with classes Vehicle, Car, and Truck. Implement methods to calculate the fuel efficiency (miles per gallon) and display information about each vehicle.
Test Cases:
Create a Car with a fuel efficiency of 30 mpg and fuel capacity of 12 gallons, verify its range is 360 miles.
Create a Truck with a fuel efficiency of 15 mpg and fuel capacity of 20 gallons, verify its range is 300 miles.
Use Case 3:
Design a class hierarchy for a library system with classes Item, Book, and DVD. Implement methods to calculate late fees for each type of item based on the number of days overdue.
Test Cases:
Create a Book with a late fee rate of $0.25 per day and 5 days overdue, verify the late fee is $1.25.
Create a DVD with a late fee rate of $0.50 per day and 3 days overdue, verify the late fee is $1.50.
Use Case 4:
Implement a hierarchy for bank accounts with classes Account, SavingsAccount, and CheckingAccount. Include methods to deposit, withdraw, and calculate interest for savings accounts.
Test Cases:
Create a SavingsAccount with an initial balance of $1000 and interest rate of 5%, deposit $500, withdraw $200, and verify the balance is $1302.50 after one year of interest.
Create a CheckingAccount with an initial balance of $2000, deposit $300, withdraw $400, and verify the balance is $1900 after deducting a $2 transaction fee for each withdrawal.