How can we achieve abstraction in Java?
Abstraction in Java is a mechanism that helps to focus on important information and hide unnecessary details from the user. It enables developers to represent real-world objects in a simplified form, making the code more readable and maintainable. There are several ways to achieve abstraction in Java, which include:
Abstract Classes: An abstract class is a class that cannot be instantiated but can be extended by other classes. Abstract classes are used to provide a general structure or blueprint for the subclasses. The subclasses can then provide the specific implementation details. An abstract class can have both abstract and concrete methods. Abstract methods are declared but have no implementation, and the subclasses must provide the implementation.
Interfaces: An interface is a collection of abstract methods and constant variables. Interfaces are used to define a contract that must be implemented by the classes that implement the interface. Interfaces provide a way to achieve abstraction because they only declare the methods, but they do not provide the implementation.
Encapsulation: Encapsulation is the mechanism of wrapping data and functions within a single unit. It helps to achieve abstraction by hiding the implementation details from the outside world, making the code more maintainable and less prone to errors. Encapsulation is achieved by making the instance variables private and providing public getter and setter methods to access the data.
Lambda Expressions: Lambda expressions are a concise way to represent functions in Java. They provide a way to achieve abstraction by enabling the developer to pass behaviour as an argument to a method. This allows for greater flexibility and code reuse.
Example 1: Abstract Class
Test.java
abstract class Shape {
abstract void draw();
}
class Rectangle extends Shape {
void draw() {
System.out.println("Drawing Rectangle");
}
}
class Circle extends Shape {
void draw() {
System.out.println("Drawing Circle");
}
}
public class Test {
public static void main(String[] args) {
Shape s = new Circle();
s.draw();
}
}
Explanation:
In this example, we have created an abstract class "Shape" with an abstract method "draw". Then, we have two subclasses "Rectangle" and "Circle" which extend the Shape class and provide their own implementation of the "draw" method.
Output:
Drawing Circle
Example 2: Interface
Test.java
/co
interface Shape {
void draw();
}
class Rectangle implements Shape {
public void draw() {
System.out.println("Drawing Rectangle");
}
}
class Circle implements Shape {
public void draw() {
System.out.println("Drawing Circle");
}
}
public class Test {
public static void main(String[] args) {
Shape s = new Circle();
s.draw();
}
Explanation:
In this example, we have created an interface "Shape" with the abstract method "draw". Then, we have two classes "Rectangle" and "Circle" which implement the Shape interface and provide their own implementation of the "draw" method.
Output:
Drawing Circle
In both examples, the abstraction mechanism helps to simplify the code by hiding the implementation details and only showing the essential features. This helps to make the code more maintainable and easier to understand.
Example 3: Encapsulation
Test.java
class Student {
private String name;
private int rollNo;
public Student(String name, int rollNo) {
this.name = name;
this.rollNo = rollNo;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getRollNo() {
return rollNo;
}
public void setRollNo(int rollNo) {
this.rollNo = rollNo;
}
}
public class Test {
public static void main(String[] args) {
Student s = new Student("John", 1);
System.out.println("Name: " + s.getName());
System.out.println("Roll No: " + s.getRollNo());
}
}
Explanation:
In this example, we have created a class "Student" with private fields "name" and "rollNo". We have also provided getter and setter methods to access and modify the values of these fields. This helps to achieve encapsulation as the internal state of the object is hidden from the outside world and can only be accessed through the public methods.
Output:
Name: John
Roll No: 1
Example 4: Polymorphism
Test.java
abstract class Shape {
abstract void draw();
}
class Rectangle extends Shape {
void draw() {
System.out.println("Drawing Rectangle");
}
}
class Circle extends Shape {
void draw() {
System.out.println("Drawing Circle");
}
}
public class Test {
public static void main(String[] args) {
Shape s1 = new Rectangle();
Shape s2 = new Circle();
s1.draw();
s2.draw();
}
}
Explanation:
In this example, we have created an abstract class "Shape" with an abstract method "draw". Then, we have two subclasses "Rectangle" and "Circle" which extend the Shape class and provide their own implementation of the "draw" method. In the main method, we have created objects of both subclasses and called the "draw" method on them. This demonstrates polymorphism as the same method "draw" is being used in multiple forms.
Output:
Drawing Rectangle
Drawing Circle