In Java, abstract classes and interfaces are used to implement abstraction. Abstract classes are similar to regular classes, but they are declared using the abstract keyword and cannot be instantiated. On the other hand, interfaces do not have any implementation code and only contain method declarations.
In Java, it is common to use abstract classes as a base for other classes. For example, suppose you are creating a program that includes various animals. In that case, you might start by creating an abstract class called Animal that contains common attributes such as sound and colour and common behaviours such as running and eating. All the specific animal classes, such as Lion, Dog, and Rabbit, would then extend the Animal class and override any necessary methods.
It's important to note that abstract classes cannot be instantiated on their own, so you would not be able to create an instance of the Animal class directly. Instead, you would create an instance of one of the specific animal classes that extends the Animal class.
class Animal {
public int legCount;
public String name;
// constructor to initialize instance variables
public Animal() {
// Implementation code
}
// methods
public String run() {
// Implementation code
}
public String makeSound() {
// Implementation code
}
}
class Lion extends Animal {
// body of class including overriding methods of Animal
}
class Dog extends Animal {
// body of class including overriding methods of Animal
}
Now we can instantiate animal classes by either using a reference variable of Animal type or their own. Consider the following example:
Lion lionObject = new Lion();
//lionObject is a type of Lion
//or we can use Animal type reference which will make the program more poylmorphic.
Animal lionObject = new Lion();
//lionObject is a type of Animal because it inherits Animal class.
These instantiations make sense. But what if we instantiate Animal class:
Animal animalObject = new Animal();
Here Animal class does not provide specific implementations for its methods, such as sound(). Therefore, it does not make sense to create an instance of the Animal class because it does not have meaningful values for its instance variables or functional implementations for its methods. Abstract classes are meant to be used as a blueprint for other classes rather than instantiated independently.
An abstract method is a method that is declared in an abstract class and does not have an implementation. It is declared using the abstract keyword and does not include a method body or curly braces.
abstract class Animal {
public abstract void makeSound();
}
class Lion extends Animal {
@Override
public void makeSound() {
System.out.println("Roar!");
}
}
In this example, the Animal class is an abstract class that contains an abstract method called makeSound(). The Lion class extends the Animal class and provides an implementation for the makeSound() method by overriding it.
The body of an abstract class can contain any type of method or variable that a regular class can, including static and final methods, constructors, and even the main() method. An abstract class may or may not contain abstract methods, which are methods that are declared but do not have an implementation.
abstract class Animal {
public int legCount;
public String name;
// constructor
public Animal(int legCount, String name) {
this.legCount = legCount;
this.name = name;
}
// abstract method
public abstract void makeSound();
// regular method
public void run() {
System.out.println("Running!");
}
}
In this example, the Animal class is an abstract class that has an instance variable called legCount and a method called makeSound() that is declared as abstract. It also has a regular method called run() that has an implementation.
To create concrete classes that represent actual animals, such as lions and dogs, you can extend the abstract Animal class and provide implementations for the abstract methods. To extend an abstract class, you use the extends clause and specify the name of the abstract class.
class Lion extends Animal {
public Lion(int legCount, String name) {
super(legCount, name);
}
@Override
public void makeSound() {
System.out.println("Roar!");
}
}
class Dog extends Animal {
public Dog(int legCount, String name) {
super(legCount, name);
}
@Override
public void makeSound() {
System.out.println("Bark!");
}
}
In this example, the Lion and Dog classes are concrete classes that extend the Animal class. They provide implementations for the abstract makeSound() method by using the @Override annotation and specifying the desired behavior. The Lion class prints "Roar!" when the makeSound() method is called, and the Dog class prints "Bark!".
If a class extends an abstract class and does not override all of its abstract methods, it is also considered an abstract class. This means that in order to use the Lion and Dog classes as concrete classes, you must override all of the abstract methods in the Animal class.
It is important to note that you can also override non-abstract, non-static, and non-final methods in an abstract class. This can be useful if you want to change the behavior of a method that is inherited from the abstract class.
abstract class Animal {
public int legCount;
public String name;
// constructor
public Animal(int legCount, String name) {
this.legCount = legCount;
this.name = name;
}
// abstract method
public abstract void makeSound();
// regular method
public void run() {
System.out.println("Running!");
}
}
class Lion extends Animal {
public Lion(int legCount, String name) {
super(legCount, name);
}
@Override
public void makeSound() {
System.out.println("Roar!");
}
@Override
public void run() {
System.out.println("Lions are fast runners!");
}
}
In this example, the Lion class extends the Animal class and overrides both the abstract makeSound() method and the non-abstract run() method. The run() method in the Lion class has a different implementation than the one in the Animal class. Note: We are calling parent class constructor from the base class constructor by using the super keyword. This involve the idea of constructor chaining.
You can then create an instance of the Lion class and call its methods as follows:
Lion lion = new Lion(4, "Lion");
lion.makeSound(); // prints "Roar!"
lion.run(); // prints "Lions are fast runners!"
Enjoy learning, Enjoy OOPS!
Subscribe to get well designed content on data structure and algorithms, machine learning, system design, object orientd programming and math.