Explain Abstraction in Java
Abstraction is a core concept in Java and object-oriented programming. It allows developers to
hide the complex details of implementation and only expose
the necessary parts of an object. Abstraction is achieved in Java using abstract classes and
interfaces. By focusing only on the essential characteristics
of an object, abstraction reduces complexity and improves the manageability of code. This
concept is essential for creating a clean and easy-to-maintain
software architecture where only relevant details are shared with the user.
Differentiate between Abstract Class and Interface
1. Abstract Class:
- Can have both abstract and concrete methods.
- Can include fields, constructors, and static methods.
- Supports inheritance by allowing only a single subclass to extend it.
- Suitable when there is a need to provide a base class with default behavior.
2. Interface:
- Contains only abstract methods (Java 8 and later allows default and static methods).
- Cannot have constructors or instance fields.
- Supports multiple inheritance by allowing a class to implement multiple interfaces.
- Best used when defining a contract that multiple classes should adhere to.
Example:
```java
abstract class Animal {
abstract void sound();
void sleep() {
System.out.println("Sleeping...");
interface Movable {
void move();
```
Explain the concept of Upcasting and Dynamic Method Dispatch
1. Upcasting:
- Upcasting is the process of treating a subclass object as if it were an instance of its
superclass. In Java, upcasting happens implicitly when an
object of a subclass type is assigned to a variable of its superclass type.
- Example:
```java
Animal animal = new Dog(); // Dog is upcasted to Animal
```
2. Dynamic Method Dispatch:
- Dynamic Method Dispatch, also known as runtime polymorphism, is the mechanism in Java
that determines which overridden method to call at runtime
based on the object being referred to. It enables Java to support runtime polymorphism by
using upcasted objects.
- Example:
```java
Animal animal = new Dog();
animal.sound(); // Calls the overridden sound() method in Dog
```
In the example, even though `animal` is of type `Animal`, the method `sound()` in `Dog` is
called due to dynamic method dispatch.