Object-oriented programming (OOP) is a crucial aspect of modern software development because it introduces features such as inheritance, encapsulation, abstraction, and polymorphism. OOP not only helps to reduce code complexity, but it also provides benefits like modularity, reusability, extensibility, and data hiding. In this blog, we have provided a fundamental overview of OOP concepts in Java.
Suppose, we need to create an application that manages student records, including their name, age, roll number, and marks in Science, English, and Mathematics. The application should also be able to perform various functions, such as calculating a student's percentage marks, changing their roll number, and increasing marks in a particular subject.
In procedural programming, we might approach this problem by creating six arrays: One for each attribute (name, age, roll number, and marks in Science, English, and Mathematics). In this case, the same index in each array would correspond to one student's information. For example, the values at index 2 in the "name" array, the "age" array, and the "roll number" array would all belong to the same student.
public class StudentDemo {
public static void main(String args[]) {
String name[] = new String[10];
int rollNumber[] = new int[10];
int age[] = new int[10];
int mathMarks[] = new int[10];
int englishMarks[] = new int[10];
int scienceMarks[] = new int[10];
// name[i] and rollNumber[i] would represent name and roll number of ith student
// Take input for these arrays
}
public float calculatePercentage(int mathMarks, int englishMarks, int scienceMarks, int maxMarksPerSubject) {
return (mathMarks + englishMarks + scienceMarks) * 100 / (float)(maxMarksPerSubject * 3);
}
// more functions to calculate different stats
}
If we need to store the address of each student, we would have to create an additional array for that purpose. If the maximum marks for each subject change, we would have to modify the arguments of the calculatePercentage() method.
Similarly, if we want to store more details about each subject, we would need another set of arrays to hold properties like subject name and subject code. All of these changes would be necessary to accommodate new requirements in the application.
As new requirements are added, the complexity of the above code will increase significantly. To make the code more efficient and reusable, we can use classes and objects. This allows us to align our thinking with the problem and reduces complexity.
The key question is: how can we transform the above solution into a class-based solution?
public class Student {
private String name;
private int age;
private int rollNumber;
private int englishMarks;
private int scienceMarks;
private int mathMarks;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// other getters and setters
public float calculatePercentage(int maxMarksPerSubject) {
return (mathMarks + englishMarks + scienceMarks) * 100 / (float)(maxMarksPerSubject * 3);
}
public void changeRollNumber(int newRollNumber) {
this.rollNumber = newRollNumber;
}
// other methods related to class Student
}
In this scenario, we have a Student class that contains all the properties or attributes of a student. In other words, this class serves as a template for each student object.
Just as we can have variables of type int, we can also have variables of type Student. Each student object will contain its own set of attribute values, which can be accessed and modified using the methods provided by the Student class. We can declare them as shown below:
Student studentA = new Student();
studentA.setName("Ayush");
Here, new Student() creates a new student object and assigns its reference to the variable studentA. We can then call the setName() method on studentA, using the syntax studentA.setName("Ayush"), to set the name of the student.
Similarly, we can call other "setter" methods on the object to set its other attributes. For example, we might use studentA.setAge(20) to set the student's age to 20. These setter methods allow us to modify the attributes of a student object after it has been created.
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
Student student[] = new Student[100];
for(int i = 0; i < 100; i++) {
student[i] = new Student();
student[i].setName(sc.nextLine());
student[i].setAge(sc.nextInt());
// take other inputs
}
}
Previously, we needed six arrays (one for each attribute) to represent a group of students. With the introduction of the Student class, we can now use a single array to represent any number of attributes and students. If we want to add a new attribute, we can modify the Student class to include it rather than create an additional array.
For example, if we need to store additional information about each subject, we can create a Subject class and use it within the Student class as shown below:
public class Subject {
String name;
String code;
int maxMarks;
// getters and setters
}
public class Student {
private String name;
private int age;
private int rollNumber;
private Subject[] subjectList;
//getters and setters
}
Using classes and objects has helped us manage this code's complexity more gracefully and elegantly. We no longer need separate attributes for different subjects because we can store and manipulate that information within the Subject class.
By defining a class for each real-world entity we wanted to represent in our code, we could map those entities to simple programming constructs. This makes it easier to understand and manipulate the code, as it more closely reflects the structure and relationships of the entities we are modelling.
An object is a specific instance of a class i.e. it represents a real entity that conforms to the specification defined by the class. A class is simply a template or blueprint for objects of a particular type, which define properties (attributes) and methods that all objects of that type should have.
In addition to reducing complexity, object-oriented programming (OOP) provides several other advantages. Before discussing these benefits, it might be helpful to review the four main concepts of OOP.
Encapsulation is the practice of bundling the data and methods that operate on that data within a single unit or object. This means that each object has its own set of data and methods, independent of the data and methods of other objects.
With encapsulation, each object has complete control over its state and behavior, and it restricts modifying an object's state from the outside. This helps to prevent inconsistencies in the object's state.
In Java, encapsulation is achieved through the use of access modifiers like private, protected, and public. By specifying the appropriate access level for each class member, we can ensure that the object's data and methods are only accessed in a way that is safe and consistent with the intended behavior of the object.
Suppose we have a class "Number" with two data members, "odd" and "even," which are always intended to be odd and even, respectively. The methods within the class ensure that these values remain odd and even. However, suppose it was possible to modify these members externally. In that case, it could lead to inconsistencies in the code and confuse other programmers using the class, as they may not be aware of the constraints the original programmer.
You can learn more about encapsulation here: Encapsulation in Object-Oriented Programming
Abstraction is the process of hiding implementation details and providing only an interface for users to access a particular functionality. For example, when driving a car, we only use the steering wheel (an interface) to change direction, but we do not need to understand how the rotation of the steering wheel causes a change in the direction of the car. Similarly, we know that pressing the brake pedal will apply the brakes, but we do not need to understand the internal workings of the brake system. Abstraction allows us to use a system without needing to understand its inner workings, making it easier to use and manage.
Suppose we have a class called "Student" with a method called "getGPA()." We can use objects of the "Student" class to call the "getGPA()" method and obtain the GPA of any student. We only need to know the signature of the method we need to call. The implementation of the method may change over time, but this does not matter to the end-user, as they are only concerned with the output returned by the method.
You can learn more about abstraction here: Abstraction in Object-Oriented Programming
In the real world, many entities share common properties and can be generalized into a more abstract entity. For example, we can create an abstract entity called "Person" to describe all people. People in the real world have common properties such as date of birth, gender, height, and weight. By creating an abstract entity, we can group these common properties together and apply them to all people. This allows us to more easily represent and work with real-world entities in a consistent and organized manner.
For example, suppose in a school, all teachers and students ultimately belong to the abstract entity "Person," as they share common properties such as date of birth, gender, height, and weight. If we need to store the details of all the teachers and students in a school, one solution is to create two classes: "Student" and "Teacher." These classes would have attributes and methods specific to each role and many common attributes and methods such as date of birth, address, and "getAge()." Code will like as shown below:
class Teacher {
private String firstName;
private String lastName;
private String address;
private Integer age;
private Long employeeId;
private Long salary;
private String grade;
// ... more properties and methods
}
class Student {
private String firstName;
private String lastName;
private String address;
private Integer age;
private Integer rollNumber;
private Integer englishMarks;
private Integer scienceMarks;
private Integer mathMarks;
// ... more properties and methods
}
Inheritance is a mechanism that allows one class to inherit the properties and methods of another class, helping to reduce redundant code and more accurately represent real-world hierarchies in programming.
In our example of a school with teachers and students, we can create a parent class called "Person" with attributes and methods that are common to all people. The "Student" and "Teacher" classes can then inherit these common properties from the "Person" class and define their own unique fields and methods. This allows us to take advantage of the shared characteristics of the "Person" class while also representing the specific features of students and teachers.
You can learn more about inheritance here: Inheritance in Object Oriented Programming
public class Person {
protected String firstName;
protected String lastName;
protected String address;
protected Integer age;
}
class Teacher extends Person {
private Long employeeId;
private Long salary;
private String grade;
// ... more properties and methods
}
class Student extends Person {
private Integer rollNumber;
private Integer englishMarks;
private Integer scienceMarks;
private Integer mathMarks;
// ... more properties and methods
public String getFullName() {
return firstName + lastName;
}
}
Polymorphism is the ability to have multiple forms, or the ability to use one interface to perform different operations depending on the context. An example of polymorphism in programming is the use of the "+" operator. When we perform 5 + 5, the result is 10. However, if we perform "5" + 5, where the first operand is a string, the result is "55," because all operands are converted to strings and concatenated.
In this example, the same operator "+" is used with different types of operands, resulting in different operations being performed. In Java, polymorphism is often implemented through method overloading and method overriding, which will be covered in more detail in a separate post.
Explore these blogs to learn more about Polymorphism:
Now that we have covered the basic concepts of object-oriented programming (OOP), it is easier to understand its advantages. Some important advantages of OOP include the following:
Enjoy learning, Enjoy OOPS :)