SLC S22 Week3 || Inheritance and Polymorphism in JAVA

Assalamualaikum my fellows I hope you will be fine by the grace of Allah. Today I am going to participate in the steemit learning challenge season 22 week 3 by @kouba01 under the umbrella of steemit team. It is about Inheritance and Polymorphism in JAVA. Let us start exploring this week's teaching course.


inheritance.png

Made with Canva

Write a Java program that creates a Person class with attributes name and age.

Here is the Java program that creates a Person class with attributes name and age. Then it create a Student class that inherits from Person and adds the attribute studentId.

image.png

Explanation of the Code

Person Class

image.png

The Person class is the base class in this program. It has two attributes: name and age, which represent the essential characteristics of a person. The class includes a constructor to initialize these attributes when a Person object is created. In addition, it provides a method called displayDetails, which outputs the name and age of the person to the console.

Student Class

image.png

The Student class inherits the properties and methods of the Person class by extension, and thus has access to them all. This is a fundamental example of the inheritance concept of object-oriented programming. The Student class also introduces an attribute, studentId, that uniquely identifies a student. To initialize all attributes, inherited and new, the Student class constructor invokes the constructor of the Person class using the super keyword and then initializes the studentId attribute. In addition, the displayDetails method in the Student class overrides the one in the Person class to include the studentId information, thus improving the functionality of the inherited method.

Main Class

image.png

The Inheritance class contains a main method which is an entry point to the program. It presents the functionality of both classes, creating objects from the Person and the Student classes. A Person object is instantiated with a name and age; its details are displayed using the displayDetails method, and then the Student object is created, with one more attribute for studentId. It then calls the displayDetails method of the Student class, where method overriding has been used to display the details of the student, including inherited and new attributes.

inheritance-ezgif.com-crop.gif

This program shows how code reuse and the extension of functionality can be accomplished using inheritance in an organized and structured manner which is an important feature of object-oriented programming.



Create a Shape class with overloaded methods area() to calculate the area of different shapes (circle, rectangle, and triangle) based on the provided parameters.

Here is the Java program which create a Shape class with overloaded methods area() to calculate the area of different shapes (circle, rectangle, and triangle) based on the provided parameters.

image.png

Here is the detailed explanation of the classes used in this program:

1. Shape Class

image.png

The Shape class illustrates the concept of method overloading, which allows multiple methods in a class to share the same name as long as their parameter lists are different. It contains three area() methods to calculate the area of a circle, rectangle, and triangle. Each method is tailored to its specific shape:

  • Circle: The first area() method takes one argument, radius, which is used in the formula Pi x radius x radius to calculate the area of the circle. The Math.PI constant supplies the value of pi and the result is returned as a double.
  • Rectangle: The second area() method has two parameters, length and width. It will compute the rectangle's area using the formula length x width.
  • Triangle: The third area() method will have three parameters: base, height, and a boolean. The boolean parameter acts as a marker to distinguish this method from the rectangle's area() method. It computes the area with the formula: 0.5×base×height.

This implementation demonstrates how method overloading allows a single class to deal with similar yet distinct operations in an efficient manner.

2. Main Class (MethodOverloading)

image.png

The main method of the MethodOverloading class will illustrate how the overloaded area() methods are utilized within the Shape class. Here, one Shape object is created, and appropriate area() methods are invoked according to the type of shape whose area needs to be computed.

  • The programme invoke the method of area(double radius) then pass the value of radius with it. The area of the circle is computed and printed.

  • The area(double length, double width) method has been invoked within the program through passing the argument of length as well as of width. So, the displayed area is of rectangle.

  • The program uses the area(double base, double height, boolean isTriangle) method and passes the base, height, and a true value for the boolean parameter. This guarantees the method meant for triangles is invoked.

methodoverloading.gif

So in this program we have used the method overloading concept through the use of the same method name area() but with different parameters. We have reused the code for the calculation of the area.

This also shows that method overloading has the versatility in improving readability and maintainability of the code.



Write a program to display the interest rates for both types of banks.

Here is a Java program that develop a Bank class with a method getInterestRate(). It creates two derived classes SavingsBank and CurrentBank that override the getInterestRate() method to return specific rates.

image.png

1. Bank Class

image.png

The Bank class is the base class with a method getInterestRate(). This method is implemented to return 0.0% as the interest rate by default. The method is overridden in the subclasses to return specific interest rates for different types of banks.


2. SavingsBank Class

image.png

The SavingsBank class is a derived class that inherits from the Bank class and overrides the getInterestRate() method to return a specific interest rate for savings accounts, which is 4.0% in this example. The @Override annotation is used to indicate that this method overrides a method from the parent class. This ensures that the method signature matches exactly with the parent method and helps catch errors during compilation.


3. CurrentBank Class

image.png

The CurrentBank class, like the previous one, extends the Bank class and has its own implementation of the getInterestRate() method. It returns a lower interest rate, in this case, 1.5% because normally, current accounts provide lower or no interest as compared to a savings account.


4. Main Class (MethodOverriding)

image.png

  • A SavingsBank object is created but referred to using a Bank type reference. This illustrates polymorphism: the overridden getInterestRate() method of SavingsBank is called at runtime.
  • Similarly, a CurrentBank object is created and its overridden getInterestRate() method is called.
  • The dynamic method dispatch ensures that the correct implementation is executed based on the actual object type even if a parent class reference is used.

methodoverriding.gif

So in this program we have used overriding method in which the derived classes SavingsBank and CurrentBank redefine the behaviour of the getInterestRate() method from the Bank class. Overriding allows the derived class to provide a specific implementation for a method already defined in its superclass. This program also uses the concept of polymorphism because it uses Bank class to override the method for the other classes.



Create a class hierarchy with a base class Vehicle and derived classes Bike and Truck.

Here is the Java program which creates a class hierarchy with a base class Vehicle and derived classes Bike and Truck. It implements a method startEngine() in the base class and override it in the derived classes to display specific messages. It uses polymorphism to call the methods through a base class reference.

image.png

1. Base Class: Vehicle

The Vehicle class acts as the base class in this hierarchy. It defines a generic method startEngine() that prints a default message: "Starting the vehicle engine...". This method can be overridden in the derived classes to provide specific behaviour for different types of vehicles.


2. Derived Class: Bike

The Bike class extends the Vehicle class and overrides the startEngine() method to display a message specific to bikes: "Starting the bike engine...". The @Override annotation is used to ensure that the method signature matches the one in the base class.


3. Derived Class: Truck

Similarly, the Truck class extends the Vehicle class and provides its own implementation of the startEngine() method. It displays the message: "Starting the truck engine...".


4. Main Class: Polymorphism

The main method demonstrates the concept of runtime polymorphism:

  1. Base Class Reference with Derived Class Object:

    • A Vehicle reference is used to point to Bike and Truck objects.
    • When the startEngine() method is called, the overridden version specific to the actual object type (i.e., Bike or Truck) is executed.
  2. Dynamic Method Dispatch:

    • Java's dynamic method dispatch mechanism ensures that the correct overridden method is invoked based on the runtime object type, not the reference type.
  3. Base Class Object:

    • A Vehicle object directly calls the startEngine() method of the base class, displaying the default message.

poly.gif

This program uses polymorphism concept because the same method (startEngine()) is called on different objects but the actual method depends on the type of the object at runtime. Moreover in this method overriding is also used because the derived classes redefine the startEngine() method to provide behaviour specific to Bike and Truck.



Build a Library Management System that uses inheritance and polymorphism.

Here is the Java program which builds a Library Management System that uses inheritance and polymorphism. It create a base class Item with attributes id, title, and isAvailable. It extends it into derived classes Book and Magazine with additional attributes. It implement polymorphic methods to borrow and return items, and display their details.

This Library Management System takes advantage of a well-structured class hierarchy with books and magazines. Each class is specifically designed to perform a different role in organizing the system's functionality and comes with the key object-oriented programming principles of inheritance, polymorphism, and encapsulation.

Base Class: Item

image.png

The base class is the Item class, representing a generic library item. It contains common attributes such as id (unique identifier), title (name of the item), and isAvailable (status of availability). This way, shared behaviors such as borrowing or returning items are implemented once.

The borrowItem() method checks whether an item is available and updates its status if it is successfully borrowed, thus giving feedback to the user. Similarly, the returnItem() method marks an item as available again. The displayDetails() method outputs basic information about the item, such as its ID, title, and availability. By encapsulating these features in the Item class, the system ensures consistency and reduces code duplication across different item types.


Derived Class: Book

image.png

The Book class is a subclass of the Item class to define the book. It inherits all the properties from the Item class and defines an additional property, author, to represent the book's author name. The Book class overrides the displayDetails() method to display the name of the author with the book details.

This is an extension of the Item class that allows the program to treat books as specialized items while reusing the core functionality for borrowing, returning, and managing availability. The Book class illustrates how inheritance can be used to add specific properties to a general structure without duplicating existing functionality.


Derived Class: Magazine

image.png

The Magazine class also extends the Item class but specifically represents magazines, which have an additional attribute called issueNumber to uniquely identify the edition or issue of the magazine. Similar to the Book class, Magazine overrides the displayDetails() method to include the issue number, illustrating how different types of items can display their details in a specific way.

The Magazine class exemplifies how inheritance supports the creation of multiple specialized classes that build upon a shared base class. This approach makes the system extensible, as new item types can be added in the future by creating additional subclasses of Item.


Main Class: LibraryManagementSystem

image.png

The LibraryManagementSystem class combines the functionality of all other classes and acts as the entry point of the program. It declares a collection of library items that is an ArrayList in which objects of both Book and Magazine types can be stored. This allows the program to manage an arbitrary number of items efficiently.

image.png

A menu-driven interface is implemented by the class, which makes it interactive for users with the library system. Users can view everything there, borrow or return by providing their ID's and exit the program. To borrow or return, the helper method "findItemById()" searches the list for an item with the particular ID set by the borrower hence very efficient in retrieval.

Errors Handling

Input Validation Using try-catch
Input validation is critical to ensure the program handles incorrect user inputs gracefully. In this program, the user input is captured using a Scanner, but if the user enters invalid data (like letters when a number is expected), it could lead to a runtime error (InputMismatchException).

image.png

To handle this, a try-catch block is used. Inside the try block, the program attempts to read the input. If the input was invalid, it would be caught by the catch and an error message would be printed. The following line of code, scanner.nextLine(), would clear off the invalid input from the buffer of the scanner and prepare it to accept further valid input. That way, there is no risk of the program crashing, but the user may correct his wrong input. Sample from the program:


Runtime Errors Handling
At times, runtime errors may occur that are not foreseen, like accessing uninitialized objects or encountering edge cases not accounted for in the program logic.

image.png

A generic catch block is added to handle any unexpected exceptions (Exception). This block acts as a safety net, printing an appropriate error message and allowing the program to continue or exit gracefully without crashing. This approach makes the program more robust by handling unforeseen issues. Example from the code:


Checking Object Searches
When searching for an item by ID, the findItemById method returns null if nothing matches the ID.

image.png

Because operations may be performed on a null object, a NullPointerException may be thrown. For safety, the program checks whether the returned object is not null before calling its methods. If the item is not found, the program will display an appropriate error message instead of trying to access the object. This is safe and predictable behavior.


Graceful Resource Cleanup
Proper resource management is a critical component of error handling. In this program, the Scanner object is used to obtain user input. After the program ends, the scanner.close() method is used to free the underlying resources used by the scanner. This helps prevent resource leaks and especially is crucial in bigger programs or applications where unused resources might impact the performance.


Default Case in the switch Statement
image.png

The menu system of the program applies a switch statement for handling user choice. In case the user provides an invalid option that doesn't match any of the defined cases, the program handles it by using a default case. This ensures that the program does not behave in ways it is not expected to or present cryptic error messages. It instead provides an explicit message that asks the user to make a valid choice.


By incorporating these layers of error handling, the program becomes more user-friendly and resilient, capable of managing a wide range of input and runtime scenarios effectively.

The program utilizes polymorphism to store Book and Magazine objects in the ArrayList as Item references. When methods such as displayDetails() are invoked, the appropriate version of the method from Book or Magazine is called at runtime based on the actual type of object. This is an example of dynamic method dispatch a central aspect of polymorphism.

This system looks like a real-world library management system where items have both shared and unique properties. And in this library management system items are already saved and the user can interact with the system to borrow or return the items by using the ID of the item.



Employee Management System

Here is the Java program for the employee management system where it tracks the data for the three types of employees according to their specific criteria for the salary. This program uses a vector to hold three employees of different types and display their details.

emp.gif

Employee Class:

image.png

  • The Employee class is an abstract class that serves as the base class for all types of employees. It contains common attributes such as name, CIN, address, and salary, along with an abstract method calculateSalary() that each derived class must implement. The display() method is implemented to print the common details of an employee.

ContractualEmployee Class:

image.png

  • The ContractualEmployee class extends the Employee class and represents employees who have a fixed monthly salary. The calculateSalary() method is implemented to set the salary to the value of the monthlySalary. The display() method is overridden to display the employee's details, including the calculated salary.

PermanentEmployee Class:

image.png

  • The PermanentEmployee class also extends the Employee class and represents employees with a base salary and a performance bonus. The calculateSalary() method calculates the salary by adding the baseSalary and performanceBonus. The display() method is overridden to display the employee's details, including base salary, bonus, and total salary.

HourlyWorker Class:

image.png

  • The HourlyWorker class extends the Employee class and represents workers who are paid based on the hours worked. The calculateSalary() method calculates the salary by multiplying the hourlyRate and hoursWorked. The display() method is overridden to display the employee's details, including hourly rate, hours worked, and total salary.

Main Program (EmployeeManagementSystem):

image.png

  • In the main() method, a Vector<Employee> is created to store different types of employees (ContractualEmployee, PermanentEmployee, and HourlyWorker).

  • Each employee is instantiated with their respective attributes and added to the employees list.

  • The program then loops through each employee in the list, calls the calculateSalary() method to calculate their salary, and calls the display() method to display the details of each employee.

  • The display() method calls from the derived classes (ContractualEmployee, PermanentEmployee, HourlyWorker) demonstrate polymorphism in action, as the correct display() method is invoked depending on the actual type of the object.

  • For the ContractualEmployee the salary is fixed at 5000 (as specified in the constructor).

  • For the PermanentEmployee the total salary is calculated as the sum of baseSalary (4000) and performanceBonus (1000) resulting in a total salary of 5000.

  • For the HourlyWorker the salary is calculated by multiplying the hourlyRate (20) by the hoursWorked (160) resulting in a total salary of 3200.

This output shows that the program correctly handles different types of employees, calculates their salaries based on their respective rules, and displays their details using the appropriate methods through polymorphism.

image.png

Here is the visual representation of the working how the derived classes are inherited from the base class. This diagram shows the perfect explanation and relationship between these classes.


Error Handling

Input Mismatch Exception Handling
image.png
This block catches specifically the errors associated with invalid input types, like when a user enters a string where a number is expected. For instance, if the input from a Scanner object is mismatched with the expected data type, this exception will be triggered. It gracefully informs the user about the issue without crashing the program.


Null Pointer Exception Handling
image.png

This block catches cases where the program attempts to access a method or property of an uninitialized object. For instance, if an employee object happens to be null when accessed, this exception will be caught. It prevents a program crash and lets the user know that a null value caused the error.


General Exception Handling
image.png

This is a catch-all block for any other exceptions that might not be explicitly handled by the previous blocks. It ensures the program can deal with unforeseen errors gracefully. This block logs the error message (e.getMessage()) to help debug while maintaining the application's robustness.


Resource Cleanup with finally Block
image.png

The finally block guarantees that critical resources like the Scanner object are released regardless of whether an exception occurs. This prevents resource leaks and ensures good resource management practices.

Each exception type is handled explicitly to address specific runtime problems:

  • InputMismatchException ensures invalid inputs don't disrupt the program.
  • NullPointerException safeguards against accessing uninitialized objects.
  • Exception provides a safety net for unanticipated errors.
  • Finally ensures cleanup of resources for reliability.

This layered approach makes the code robust, user-friendly, and maintainable.



Given the following class definitions, analyze whether the instructions 1 to 8 in the main method are valid.

Here is the break down of each instruction based on the class hierarchy and Java rules for type assignment and casting. The class hierarchy is shown below:

C1 (Base Class)
└── C11 (Derived from C1)
    └── C111 (Derived from C11)

Analysis

  1. Instruction 1:
    o1 = o2;
    • Explanation: o2 is of type C1 and is assigned an object of C11. Since o1 is of type C1, this assignment is valid because o2 is compatible with o1.
    • Result: Valid.
  2. Instruction 2:
    o1 = o3;
    • Explanation: o3 is of type C111, which is a subclass of C1. Because o1 is of type C1, this assignment is valid based on upward compatibility in the class hierarchy.
    • Result: Valid.
  3. Instruction 3:
    o3 = o1;
    • Explanation: o1 is of type C1, and o3 is of type C111. Direct assignment is not allowed because o1 may refer to an object of a superclass that is not compatible with C111.
    • Result: Invalid (compilation error).
  4. Instruction 4:
    o4 = o5;
    • Explanation: o5 is of class C1 but actually referring to an object of C111. Because o4 is of class C11 and C111 is a subclass of C11, this assignment is valid.
    • Result: Valid.
  5. Instruction 5:
    o3 = (C111) o1;
    • Explanation: o1 is of type C1, but it may not refer to a C111 object. A cast is needed, but it may throw a runtime exception (ClassCastException) if o1 does not actually refer to a C111 object.
    • Result: Possible runtime error.
  6. Instruction 6:
    o4 = (C11) o5;
    • Explanation: o5 is of type C1 but refers to a C111 object. A cast to C11 is valid because C111 is a subclass of C11.
    • Result: Valid.
  7. Instruction 7:
    o4 = (C111) o2;
    • Explanation: o2 is of type C1 and is referencing a C11, not a C111. Casting to C111 is valid, but will result in a runtime exception (ClassCastException) because o2 does not reference a C111.
    • Result: Runtime error.
  8. Instruction 8:
    o3 = (C11) o5;
    • Explanation: o5 is of type C1 but refers to a C111 object. Casting a C111 object to C11 is legal because C111 is a subclass of C11. But o3 is of type C111, and assigning a C11 reference to a C111 variable will result in a compile-time error.
    • Result: Not Legal (compile-time error).

Summary Table

InstructionValid/InvalidError Type
1Valid
2Valid
3InvalidCompilation Error
4Valid
5Possible runtime errorClassCastException
6Valid
7Runtime errorClassCastException
8InvalidCompilation Error

Key Points

  1. Upcasting (assigning a derived class object to a base class reference) is always valid without a cast.
  2. Down casting-that is, making a reference to a derived class that was already holding a base class reference must be explicitly performed and succeeds only if the base class reference is actually referencing an instance of the derived class.
  3. When an invalid cast is used at runtime, ClassCastException is raised whereas type incompatible assignment will lead to compile-time errors.


Create a Point class with attributes x (abscissa) and y (ordinate). Include constructors Point() and Point(x, y). Add getters, setters, and a toString() method.

Point Class

image.png

The Point class is a base class within this class inheritance hierarchy. This class represents the 2D point with members for x (abscissa) and y (ordinate). It contains a no-arg default constructor that inits both x and y to 0.0. It also provides a parameterized constructor that permits the initialization of x and y with arguments.

Additionally, this class provides getters and setters for both x and y, ensuring controlled access to these values.

The toString method is overridden to provide a string representation of the point, making it easy to display the object's coordinates in a readable format like "Point(x=2.5, y=3.5)". This class acts as the base class for all the geometric shapes in the hierarchy.


Rectangle Class

image.png

The Rectangle class extends the Point class, adding the attributes length and width to describe a rectangle in terms of these two dimensions. It supports both a default constructor that initializes x, y, length, and width all to 0.0 as well as a parameterized constructor for initializing them to any given values:.

Getters and setters are provided for length and width, which makes it easier to manipulate these properties. There is also an area method that computes the area of the rectangle, using the formula length * width.

In addition, the toString method is overridden to include the rectangle's dimensions and its calculated area. This will return a detailed string representation that includes both inherited and specialized information.


Parallelogram Class

image.png

The Parallelogram class extends the Rectangle class with an additional attribute to represent the perpendicular height of the parallelogram. It includes a default constructor which initializes all attributes to 0.0, including x, y, length, width, and height; it also contains a parameterized constructor with specific values for these attributes.

This class provides a getter and setter for the height attribute that allows the modification of the parallelogram height. The area method has overridden the formula in its base class rectangle in order to obtain the area with the formula of length * height.

In addition to the area, the Parallelogram class also defines a volume method, assuming the parallelogram forms a prism. This method calculates the volume by using the formula area * width. Lastly, the toString method is overridden to provide a more detailed string representation that includes the height of the parallelogram, its area, and volume, in addition to the inherited rectangle properties.


GeometricTest Class

image.png

The GeometricTest class is a test driver for this program that shows how the classes work in practice. In the class, instances of Point, Rectangle, and Parallelogram are created to show the behavior of each class.

For both instances of Rectangle and Parallelogram, the area method is called, and for the instance of Parallelogram the volume method is also called to show its added functionality.

The toString method is employed to print detailed information for every object: the coordinates, the dimensions, area, and for the parallelogram - the volume.

image.png

The test class actually shows how inheritance and overriding methods work to smoothly go through one geometric figure after another and keep the program flexible and easy to read in its design.



I invite @wilmer1988, @josepha, @wuddi to join this learning challenge.



Sort:  
Loading...
Loading...

Coin Marketplace

STEEM 0.29
TRX 0.24
JST 0.041
BTC 93056.65
ETH 3262.68
USDT 1.00
SBD 7.63