Day 4: Java OOPS Part 2

Day 4: Java OOPS Part 2

Inheritance in Java

Inheritance is a concept in object-oriented programming where a new class (called the "subclass" or "derived class") is created by inheriting the properties and methods of an existing class (called the "superclass" or "base class"). The subclass can then add its own properties and methods, or override the properties and methods of the superclass.

In Java, inheritance is achieved using the "extends" keyword. Here's an example:

// Define a superclass called "Vehicle"
public class Vehicle {
?String make;
?String model;
?int year;
??
?public Vehicle(String make, String model, int year) {
??this.make = make;
??this.model = model;
??this.year = year;
?}
??
?public void startEngine() {
??System.out.println("Starting the engine...");
?}
}

// Define a subclass called "Car" that inherits from "Vehicle"
public class Car extends Vehicle {
?int numDoors;
??
?public Car(String make, String model, int year, int numDoors) {
??super(make, model, year);
??this.numDoors = numDoors;
?}
??
?@Override
?public void startEngine() {
??System.out.println("Starting the car engine...");
?}
??
?public void accelerate() {
??System.out.println("Accelerating...");
?}
}

// Create an object of the Car class and call its methods
Car myCar = new Car("Toyota", "Camry", 2021, 4);
myCar.startEngine();
myCar.accelerate();

In this example, we defined a superclass called "Vehicle" with variables to hold the state of a vehicle and a method to start the engine. We then defined a subclass called "Car" that inherits from "Vehicle" and adds a new variable called "numDoors" and a new method called "accelerate()".

To inherit from the superclass, the subclass uses the "extends" keyword followed by the name of the superclass. The subclass constructor calls the superclass constructor using the "super" keyword to initialize the inherited variables. We also override the startEngine() method in the Car class to provide a different implementation.

There are four types of inheritance possible in Java:

Single inheritance:

where a subclass inherits from a single superclass.

Multi-level inheritance:

where a subclass inherits from a superclass, which itself inherits from another superclass, and so on.

Hierarchical inheritance:

where multiple subclasses inherit from the same superclass.

Multiple inheritance:

where a subclass inherits from multiple superclasses (not supported in Java, but can be achieved using interfaces).

How to achieve multiple inheritance in Java?

In Java, single inheritance and multi-level inheritance are possible using the "extends" keyword, while hierarchical inheritance can be achieved by creating multiple subclasses that inherit from the same superclass. Multiple inheritance is not supported in Java, but can be achieved using interfaces.

In Java, multi-level inheritance is allowed, which means a class can inherit properties and behavior from its parent class, which in turn can inherit from its parent class. However, Java does not allow multiple inheritance, which means a class cannot inherit properties and behavior from multiple parent classes at the same time.

The reason for not allowing multiple inheritance in Java is to avoid the diamond problem. The diamond problem occurs when two parent classes of a class have a common method and the subclass tries to call that method. In this case, it is ambiguous which implementation of the method should be called, leading to confusion and errors.

For example, let's say we have two classes called "A" and "B" that both have a method called "myMethod()". We then define a class called "C" that inherits from both "A" and "B". If "C" tries to call the "myMethod()" method, it is unclear which implementation of the method should be called - the one in "A" or the one in "B". This ambiguity is the diamond problem and can lead to errors and confusion.

Java solves this problem by not allowing multiple inheritance. Instead, it allows for the use of interfaces, which are similar to classes but cannot have implementations for their methods. This allows multiple inheritance of behavior without the diamond problem.

Here is an example that demonstrates multiple inheritance of interfaces in Java:

interface A {
?void foo();
}

interface B {
?void bar();
}

class MyClass implements A, B {
?public void foo() {
??System.out.println("foo method from interface A");
?}
?public void bar() {
??System.out.println("bar method from interface B");
?}
}

public class Main {
?public static void main(String[] args) {
??MyClass myClass = new MyClass();
??myClass.foo(); // Output: "foo method from interface A"
??myClass.bar(); // Output: "bar method from interface B"
?}
}

In this example, we define two interfaces A and B with a single method each. Then we define a class MyClass that implements both A and B interfaces and provides the implementations for their methods. Finally, in the main method, we create an object of MyClass and call the methods foo and bar from the implemented interfaces.

Here, MyClass is inheriting from multiple interfaces A and B simultaneously, which is known as multiple inheritance of interfaces in Java.


Polymorphism

Polymorphism is another important concept in object-oriented programming and refers to the ability of an object to take on multiple forms. In Java, polymorphism can be achieved in two ways: through method overloading and method overriding.

Method overloading

refers to the practice of defining multiple methods with the same name but with different parameters or argument lists. When a method is called, the compiler decides which version of the method to execute based on the number and types of arguments passed to it. Here's an example:

public class Math {
?public int add(int a, int b) {
??return a + b;
?}
??
?public double add(double a, double b) {
??return a + b;
?}
}

In this example, we define two methods called "add()" with different argument lists: one that takes two integers and returns an integer, and one that takes two doubles and returns a double. When the "add()" method is called, the compiler decides which version of the method to execute based on the types of the arguments passed to it. This is an example of method overloading.

Method Overriding

refers to the practice of providing a new implementation for an existing method in a subclass. When a method is called on an object of the subclass, the new implementation in the subclass is executed instead of the implementation in the superclass. Here's an example:

// Define a superclass called "Animal"
public class Animal {
?public void makeSound() {
??System.out.println("The animal makes a sound");
?}
}

// Define a subclass called "Dog" that overrides the "makeSound()" method
public class Dog extends Animal {
?@Override
?public void makeSound() {
??System.out.println("The dog barks");
?}
}

// Create objects of both classes and call their "makeSound()" methods
Animal myAnimal = new Animal();
Dog myDog = new Dog();

myAnimal.makeSound();
myDog.makeSound();

In this example, we define a superclass called "Animal" with a method called "makeSound()". We then define a subclass called "Dog" that overrides the "makeSound()" method with its own implementation. When the "makeSound()" method is called on an object of the Dog class, the new implementation in the Dog class is executed instead of the implementation in the Animal class. This is an example of method overriding.

In Java, polymorphism can be further categorized into two types:

Compile-time polymorphism:

This is achieved through method overloading, where the compiler decides which version of the method to execute based on the number and types of arguments passed to it. This type of polymorphism is also called static polymorphism or method overloading.

Runtime polymorphism:

This is achieved through method overriding, where the decision of which method to execute is made at runtime based on the actual object type. This type of polymorphism is also called dynamic polymorphism or method overriding.

Both types of polymorphism have their own advantages and are better suited for different situations. Method overloading is useful when we want to provide multiple ways of performing the same operation with different arguments, while method overriding is useful when we want to provide a new implementation for an existing method in a subclass.




要查看或添加评论,请登录

Shree Krishna Priya J的更多文章

社区洞察

其他会员也浏览了