Java is a programming language that is based on OOPs concepts (Object-oriented programming system). In other words, it uses objects to define the data and their behavior. This makes the code more flexible and increases the readability and helps to understand the code easier. In this tutorial, we will understand OOPs concepts in Java.
Table of Contents
Characteristics of OOPs in Java
Advantages of OOPs Concepts in Java
- Reduces code redundancy
- Improves code readability
- Low development cost
- Improved software quality
- Faster product development
- Reusability of code
Challenges of OOPs in Java
- High learning curve
- Large program size
- Slow execution
Object
One of the important features of Object-oriented programming in Java is an object. An object represents a real-life entity which is an instance of a class. It contains both data and methods(behaviors). Objects have mainly 2 characteristics of state and behaviors. The state is nothing but an identity of the object(data) and behavior describes the function(method) of the object.
Example:
Object: Mobile
State: Name, Model No, Color
Behavior: Calling, messaging, switch on, switch off, take photos, etc.
Let’s understand this with an example. Here class name is Mobile and it has attributes or states as mobilename, modelNumber, and color. In java programming, we call these attributes as variables and behaviors as methods.
The methods are call(), message(), switchOn() and switchOff().
The object name is m which is an instance of the class Mobile. Using this object m, we can access the attributes and methods.
public class Mobile { //Attributes String mobilename; String modelNumber; String color; //Methods public void call() { } public void message() { } public void switchOn() { } public void switchOff() { } public static void main(String[] args) { Mobile m = new Mobile(); } }
Class
A class can be defined as a prototype or a blueprint from which we can create multiple objects. In other words, it is nothing but a group of entities. Any java program we write should be written as a class which is yet another feature of object-oriented programming in java.
Example:
Class: Person
Object: Male or Female
State: Name, Age
Behavior: Eating, Walking, Cooking, etc
Below is an example of creating a class with multiple objects and how to access the data and variables. Here we have created a class named Person with 2 objects male and female. With these 2 objects, we can access all the attributes and methods of the class which is the main usage of objects. It reduces redundancy and improves code readability. We have also created a constructor for the class which gets invoked when the object is created. To understand more on constructors, please refer to constructors in java tutorial.
public class Person { //Attributes String name; int age; Person(String name, int age){ this.name = name; this.age = age; } public void eating() { System.out.println("Eating"); } public void walking() { System.out.println("Walking"); } public static void main(String[] args) { Person male = new Person("Dev",35); Person female = new Person("Devika",20); System.out.println(male.name + " " + male.age); male.eating(); System.out.println(female.name + " " + female.age); female.walking(); } }
Dev 35 Eating Devika 20 Walking
OOPs concepts – Abstraction
Abstraction is one of the main OOPs concepts in Java. It mainly defines what kind of data needs to be visible and what needs to be hidden. In other words, it just provides the methods and not the internal functionality. For example, when we use a mobile phone, we just know its behavior but we don’t know the inner mechanism of how it works. We can use abstraction to make the application more secure. For example, when we log in to net banking and provide username and password, the password is actually hidden.
We can use this feature of object-oriented programming in java for a class, data, or a method. To implement abstraction, we use interfaces and abstract classes. Let’s understand this OOPs concept in Java in detail below.
Abstract Class
To create an abstract class or method, we use the abstract keyword.
If we create an abstract class, then it means we cannot create an object for this class. Also, an abstract class can have an abstract method and normal methods as well. If a class contains an abstract method, then we should declare the class as abstract.
Abstract class contains only a method declaration and there is no implementation. For this, we need to use inheritance and implement the abstract method functionality by extending the abstract class. It is mandatory to implement all the abstract methods of the abstract class else it will throw compile error.
Example of Abstract class and method
Here, we have created an abstract class Scores since it contains 2 abstract methods and 1 normal method. The abstract methods getMarks and setMarks have only declarations and no implementation which means it does not contain any code within the function. We also have a non-abstract method getName with functionality within it.
/*Filename: Scores.java */
//Abstract class public abstract class Scores { String name; abstract int getMarks(); //abstract method abstract void setMarks(int marks);//abstract method //non abstract method public String getName() { return name; } }
Next, we create another class College. In order to implement the abstract methods of the abstract class Scores, we need to extend the abstract class using the keyword extends. We provide all the implementations of the abstract methods in this class. We then create an object c for the class College and access these methods and data.
/*Filename: College.java */
public class College extends Scores { public int marks; public int getMarks() { return marks; } public void setMarks(int marks) { this.marks = marks; } public static void main(String[] args) { College c = new College(); c.name = "Harish"; c.setMarks(80); System.out.println("Student Name: " + c.name); System.out.println("Student Marks: " + c.getMarks()); } }
Student Name: Harish Student Marks: 80
The main idea of abstraction is that even though the functionality is the same, the way it needs to be implemented can be different for each class. This provides more flexibility.
For example, below is another class School which extends the same abstract class Scores. But if you notice, we can see that the implementation of the abstract methods is different here. We have the flexibility to change the implementation of the method. In this example, we have added 5 to the marks in getMarks method and added 2 to the setMarks method.
/*Filename: School.java */
public class School extends Scores{ int marks; public int getMarks() { return marks+5; } public void setMarks(int marks) { this.marks = marks+2; } public static void main(String[] args) { School s = new School(); s.name = "Harsha"; s.setMarks(80); System.out.println("Student Name: " + s.name); System.out.println("Student Marks: " + s.getMarks()); } }
Student Name: Harsha Student Marks: 87
Interface
An interface is also similar to a class but contains a group of abstract methods. It does not contain the method implementation but has only method definition. To implement the functionality of these abstract methods, we need to use inheritance. One difference between abstract class and interface is that an interface cannot have non-abstract methods. The interface is another way of achieving abstraction which is also an important OOPs concept in Java
Example of interface
In this example, we have created an interface Shapes which has a method calculateArea. In an interface, we provide only method declaration and there is no implementation. To implement this method, we need to define another class.
public interface Shapes { public void calculateArea(); }
Here we have a class Rectangle that implements Shapes class. For this, we use the implements keyword. This class provides the functionality of the method calculateArea. The main idea of this OOPs concept in Java is to provide flexibility for any class to implement the functionality in a different way.
public class Rectangle implements Shapes { public void calculateArea() { int l = 4; int b = 5; int area = l*b; System.out.println("Area: " + area); } public static void main(String[] args) { Rectangle r = new Rectangle(); r.calculateArea(); } }
Area: 20
We can also create another class named Square and implement Shapes class. This class can implement the calculateArea method in another way as below. Hence the method calculateArea can be implemented based on each class specification that implements the interface.
public class Square implements Shapes { public void calculateArea() { int l = 4; int area = l*l;; System.out.println("Area: " + area); } public static void main(String[] args) { Square s = new Square(); s.calculateArea(); } }
Area: 16
OOPs concepts – Encapsulation
Encapsulation is another OOPs concept in Java that binds the data and its method from external interference. This means it does not allow other classes to access or update these data or methods directly. One good example is the Java class itself which tightly binds the data and its functions within the class. To achieve this, we declare the variables or data as private variables. We will discuss what is a private variable in detail in further tutorials about access modifiers. For now, just remember that private variables cannot be accessed outside a class. To access and update these data, we must use public get and set methods. We cannot access these private variables directly from other classes. Hence encapsulation helps to hide sensitive data from the user. It is also called data hiding.
One best example of encapsulation is a capsule itself (as the name suggests) inside which we have medicine which is not visible to us.
Example
Let’s understand this OOPs concept of Encapsulation using an example. We have created Student.java class with private variables name and age. To access the variables from other classes, we need to use getName, setName, getAge, and setAge methods. These are called getters and setters in object-oriented programming in java.
/* File Name: Student.java */
public class Student { private String name; private int age; public String getName() { return name; } public void setName(String studentname) { this.name = studentname; } public int getAge() { return age; } public void setAge(int studentage) { this.age = studentage; } }
/* File Name : Department.java */
We have created another class Department and from here we are trying to access the private variables of the Student class. So for this, we can use the getters and setters method accordingly. Hence this class does not know the inner implementation of the getter and setter methods. It just knows that getName will help to get the student name and setName will help to set the student name. This is the main idea of this OOPs concept in Java which is generally used in developing any application.
public class Department { public static void main(String[] args) { Student s = new Student(); s.setName("Arthi"); s.setAge(32); System.out.println("Student Name: " + s.getName()); System.out.println("Student Age: " + s.getAge()); } }
Student Name: Arthi Student Age: 32
Suppose we try to access these private variables directly from another class without using the methods, we will get an error as below. Since these variables are private, it will throw an error as it is not visible,
public class Department { public static void main(String[] args) { Student s = new Student(); s.name = "Arthi"; s.age = 32; } }
Exception in thread "main" java.lang.Error: Unresolved compilation problems: The field Student.name is not visible The field Student.age is not visible at Department.main(Department.java:8)
OOPs concepts – Inheritance
When one class can reuse the methods and variables of another class, we call this OOPs concept in Java as Inheritance. This class can reuse the other classes’ data and functions by extending to that class using the extends keyword. The parent class is called the base class or superclass and the class that extends the parent class is called the child class or subclass or derived class. In other words, using this OOPs concept in Java, we can define a new class using the existing class by inheriting all the variables and methods.
The main use of this feature of Object-oriented programming in java is to support the is-a relationship. For example:
- Car is a vehicle
- Violin is an instrument
- A laptop is a gadget
All words after is-a denote the parent class and all words before is-a denote the subclass.
Syntax
class A { //code } class B extends class A { //code }
Class A is the parent class and Class B is the child class.
extends is the keyword that supports Inheritance OOPs concept in Java
Now that we have an idea about this main OOPs concept in Java named Inheritance, let’s look into its details with a simple example.
Example of Inheritance
Here Vehicle is the parent class which contains a string variable name and 4 different methods startVehicle(), applyBrakes(), stopVehicle(), and setName. It also contains the function implementation.
/*Filename: Vehicle.java */ – Parent Class
public class Vehicle { String name; public void startVehicle() { System.out.println("Starting the vehicle"); } public void applyBrakes() { System.out.println("Apply brakes"); } public void stopVehicle() { System.out.println("Stopping the vehicle"); } public void setName(String name) { this.name = name; } }
/*Filename: Car.java */ – Child class
Now, we create another class named Car.java and extend it from the Vehicle class. So the Car class becomes the child class. This class can inherit all the variables and methods of the Vehicle class as you can see in the below code. It is not necessary to declare them again in the child class.
We just need to create an object for the Car class and access the data and methods using this object. In simple words, we can say that a car is a vehicle. Hence inheritance in java supports is-a relationship.
public class Car extends Vehicle{ public static void main(String[] args) { Car c = new Car(); c.setName("BMW"); System.out.println("Vehicle name: " + c.name); c.startVehicle(); c.applyBrakes(); c.stopVehicle(); } }
Vehicle name: BMW Starting the vehicle Apply brakes Stopping the vehicle
Types of Inheritance
There are different types of Inheritance as described below:
Single Inheritance
When one class extends another class, we call it a single inheritance which creates a parent-child relationship.
Multilevel Inheritance
When a child class extends another child class(a class that extends a parent class), we call it a multilevel inheritance. For example, Class C extends Class B and Class B extends Class A.
Hierarchical Inheritance
When more than 1 class extends the same parent class, we call it a hierarchical inheritance. For example, Class B and Class C extend Class A.
Hybrid Inheritance
Hybrid inheritance contains multiple types of inheritance. For example, Class B and Class C extend Class A(Hierarchical) and Class D extends Class B.(single)
There is also another type of inheritance named Multiple Inheritance where the class extends more than 1 parent class. But this is not supported in Java but is supported in C++.
We will understand in detail about the Inheritance types in a separate tutorial.
OOPs concepts – Polymorphism
Polymorphism, as the name suggests, means having “multiple forms“. This is another important OOPs concept in Java which is used commonly in developing many software applications where we can have different implementation of the same method.
Let us understand this feature of object-oriented programming in java with an example. For example, each bike type can have different speed capacity. Slow speed bikes like TVS 50 speed capacity is slow when compared to medium speed bikes like Honda Access and this might be slow when compared to High-speed bikes like Pulsar. Hence even though all the 3 types of bikes have speed, the implementation differs from one another.
Example of Polymorphism
/*Filename: Bike.java */ Parent class
Here we have class Bike which is a parent class and has a method speed() with a statement as “Default speed”.
public class Bike { public void speed() { System.out.println("Default speed"); } }
/*Filename: SlowBike.java */ – Child class
Next, we create a subclass SlowBike which extends the base class and has the same method speed() but with a different statement as slow speed. When we create an object from SlowBike class and call the speed method, it prints “slow speed”. But if we create an object from Bike class, then it prints “default speed”.
public class SlowBike extends Bike { public void speed() { System.out.println("Slow speed"); } public static void main(String[] args) { Bike slow = new SlowBike(); slow.speed(); Bike b = new Bike(); b.speed(); } }
Slow speed Default speed
/*Filename: MediumBike.java */
Similarly, we can have another subclass MediumBike that extends the superclass. So when we call the speed() method using this class object it prints “Medium speed”.
public class MediumBike extends Bike { public void speed() { System.out.println("Medium speed"); } public static void main(String[] args) { Bike medium = new MediumBike(); medium.speed(); } }
Medium speed
Types of Polymorphism
There are 2 types of polymorphism:
- Static Polymorphism – This is also called as compile-time polymorphism.
- Dynamic Polymorphism – This is called runtime polymorphism.
Static Polymorphism
When polymorphism is resolved during compile time, we call it as static polymorphism. One best example is method overloading. This means we can have multiple methods of the same name in a class but having different signatures(parameters).
Example:
This is an example of static polymorphism or method overloading where we have the same method add but with different parameter lists. During compile-time, based on the parameters, it decides which method to call. First, the add method has 2 integers as parameters and the second add method has 2 double as parameters. When we call add method with an integer, the first method is called and when we call with double the second method is called.
public class StaticDemo { public void add(int a, int b) { int sum = a + b; System.out.println("Sum: " + sum); } public void add(double x, double y) { double sum = x + y; System.out.println("Sum: " + sum); } public static void main(String[] args) { StaticDemo d = new StaticDemo(); d.add(4, 5); d.add(3.2, 5.2); } }
Sum: 9 Sum: 8.4
Dynamic Polymorphism
When polymorphism is resolved during runtime, we call it as dynamic polymorphism. Method overriding is an example of dynamic polymorphism. Here, JVM decides during runtime which method has to be called since both the parent class and child class contains the same method name. Let’s recall the first example we saw in polymorphism which is dynamic polymorphism.
Example:
/*Filename: Bike.java */ Parent class
Here we have class Bike which is a parent class and has a method speed() with a statement as “Default speed”.
public class Bike { public void speed() { System.out.println("Default speed"); } }
/*Filename: HighBike.java */
In the same way, we can have another subclass FastBike that extends the superclass. So when we call the speed() method using this class object it prints “High speed”.
public class FastBike extends Bike { public void speed() { System.out.println("High speed"); } public static void main(String[] args) { Bike high = new FastBike(); high.speed(); } }
High speed
In the above example, both the classes have the same method name speed. During runtime, the JVM decides which method to call. Based on for which class we create an object, the corresponding method will be called. Here since we are creating an object for class FastBike it calls that class method.
Suppose we are invoking as in the below code. It will call the Bike class method and prints “Default speed”
Bike high = new Bike(); high.speed();
Default speed
We will discuss in detail about different polymorphism types with more examples in a separate tutorial.