explain polymorshisim in java

Polymorphism in Java is the ability of an object to take different forms or behave differently based on the context. There are two types of polymorphism: compile-time polymorphism (method overloading) and run-time polymorphism (method overriding).

1. Compile-time polymorphism (method overloading): This occurs when there are multiple methods with the same name in a class, but with different parameters. The correct method to be executed is determined by the number or type of parameters passed to it during compilation.

Example of compile-time polymorphism:
```java
public class Calculator {
public int add(int a, int b) {
return a + b;
}

public double add(double a, double b) {
return a + b;
}
}
```

2. Run-time polymorphism (method overriding): This occurs when a subclass provides a specific implementation of a method that is already defined in its superclass. The overridden method is executed based on the actual object type at runtime.

Example of run-time polymorphism:
```java
public class Shape {
public void draw() {
System.out.println("Drawing a shape");
}
}

public class Circle extends Shape {
@Override
public void draw() {
System.out.println("Drawing a circle");
}
}

public static void main(String[] args) {
Shape s = new Circle();
s.draw(); // Output: Drawing a circle
}
```

Polymorphism allows for more flexibility and reusability in code by enabling objects to behave differently based on their specific types or contexts.