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.
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
.
Explanation of the Code
Person Class
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
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
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.
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.
Here is the detailed explanation of the classes used in this program:
1. Shape Class
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 formulaPi x radius x radius
to calculate the area of the circle. TheMath.PI
constant supplies the value ofpi
and the result is returned as adouble
. - Rectangle: The second
area()
method has two parameters,length
andwidth
. It will compute the rectangle's area using the formulalength x width
. - Triangle: The third
area()
method will have three parameters:base
,height
, and aboolean
. Theboolean
parameter acts as a marker to distinguish this method from the rectangle'sarea()
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)
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 atrue
value for theboolean
parameter. This guarantees the method meant for triangles is invoked.
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.
1. Bank Class
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
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
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)
- A
SavingsBank
object is created but referred to using aBank
type reference. This illustrates polymorphism: the overriddengetInterestRate()
method ofSavingsBank
is called at runtime. - Similarly, a
CurrentBank
object is created and its overriddengetInterestRate()
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.
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.
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:
Base Class Reference with Derived Class Object:
- A
Vehicle
reference is used to point toBike
andTruck
objects. - When the
startEngine()
method is called, the overridden version specific to the actual object type (i.e.,Bike
orTruck
) is executed.
- A
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.
Base Class Object:
- A
Vehicle
object directly calls thestartEngine()
method of the base class, displaying the default message.
- A
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
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
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
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
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.
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
).
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.
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.
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
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.
Employee Class:
- The
Employee
class is an abstract class that serves as the base class for all types of employees. It contains common attributes such asname
,CIN
,address
, andsalary
, along with an abstract methodcalculateSalary()
that each derived class must implement. Thedisplay()
method is implemented to print the common details of an employee.
ContractualEmployee Class:
- The
ContractualEmployee
class extends theEmployee
class and represents employees who have a fixed monthly salary. ThecalculateSalary()
method is implemented to set thesalary
to the value of themonthlySalary
. Thedisplay()
method is overridden to display the employee's details, including the calculated salary.
PermanentEmployee Class:
- The
PermanentEmployee
class also extends theEmployee
class and represents employees with a base salary and a performance bonus. ThecalculateSalary()
method calculates the salary by adding thebaseSalary
andperformanceBonus
. Thedisplay()
method is overridden to display the employee's details, including base salary, bonus, and total salary.
HourlyWorker Class:
- The
HourlyWorker
class extends theEmployee
class and represents workers who are paid based on the hours worked. ThecalculateSalary()
method calculates the salary by multiplying thehourlyRate
andhoursWorked
. Thedisplay()
method is overridden to display the employee's details, including hourly rate, hours worked, and total salary.
Main Program (EmployeeManagementSystem
):
In the
main()
method, aVector<Employee>
is created to store different types of employees (ContractualEmployee
,PermanentEmployee
, andHourlyWorker
).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 thedisplay()
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 correctdisplay()
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) andperformanceBonus
(1000) resulting in a total salary of 5000.For the HourlyWorker the salary is calculated by multiplying the
hourlyRate
(20) by thehoursWorked
(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.
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
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
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
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
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
- Instruction 1:
o1 = o2;
- Explanation:
o2
is of typeC1
and is assigned an object ofC11
. Sinceo1
is of typeC1
, this assignment is valid becauseo2
is compatible witho1
. - Result: Valid.
- Explanation:
- Instruction 2:
o1 = o3;
- Explanation:
o3
is of typeC111
, which is a subclass ofC1
. Becauseo1
is of typeC1
, this assignment is valid based on upward compatibility in the class hierarchy. - Result: Valid.
- Explanation:
- Instruction 3:
o3 = o1;
- Explanation:
o1
is of typeC1
, ando3
is of typeC111
. Direct assignment is not allowed becauseo1
may refer to an object of a superclass that is not compatible withC111
. - Result: Invalid (compilation error).
- Explanation:
- Instruction 4:
o4 = o5;
- Explanation:
o5
is of classC1
but actually referring to an object ofC111
. Becauseo4
is of classC11
andC111
is a subclass ofC11
, this assignment is valid. - Result: Valid.
- Explanation:
- Instruction 5:
o3 = (C111) o1;
- Explanation:
o1
is of typeC1
, but it may not refer to aC111
object. A cast is needed, but it may throw a runtime exception (ClassCastException) ifo1
does not actually refer to aC111
object. - Result: Possible runtime error.
- Explanation:
- Instruction 6:
o4 = (C11) o5;
- Explanation:
o5
is of typeC1
but refers to aC111
object. A cast toC11
is valid becauseC111
is a subclass ofC11
. - Result: Valid.
- Explanation:
- Instruction 7:
o4 = (C111) o2;
- Explanation:
o2
is of typeC1
and is referencing aC11
, not aC111
. Casting toC111
is valid, but will result in a runtime exception (ClassCastException) becauseo2
does not reference aC111
. - Result: Runtime error.
- Explanation:
- Instruction 8:
o3 = (C11) o5;
- Explanation:
o5
is of typeC1
but refers to aC111
object. Casting aC111
object toC11
is legal becauseC111
is a subclass ofC11
. Buto3
is of typeC111
, and assigning aC11
reference to aC111
variable will result in a compile-time error. - Result: Not Legal (compile-time error).
- Explanation:
Summary Table
Instruction | Valid/Invalid | Error Type |
---|---|---|
1 | Valid | — |
2 | Valid | — |
3 | Invalid | Compilation Error |
4 | Valid | — |
5 | Possible runtime error | ClassCastException |
6 | Valid | — |
7 | Runtime error | ClassCastException |
8 | Invalid | Compilation Error |
Key Points
- Upcasting (assigning a derived class object to a base class reference) is always valid without a cast.
- 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.
- 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
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
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
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
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.
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.